Merge branch 'jl777-FSM'

x
This commit is contained in:
blackjok3r
2019-02-18 19:10:19 +08:00
130 changed files with 45226 additions and 1915 deletions

10
.gitignore vendored
View File

@@ -11,7 +11,7 @@ src/test/test_bitcoin
*zcashTest.vk
# autoreconf
Makefile.in
#Makefile.in
aclocal.m4
autom4te.cache/
build-aux/config.guess
@@ -29,7 +29,7 @@ build-aux/compile
build-aux/test-driver
config.log
config.status
configure
#configure
libtool
src/config/bitcoin-config.h
src/config/bitcoin-config.h.in
@@ -126,3 +126,9 @@ src/komodo-tx.exe
src/cryptoconditions/compile
src/cc/rogue/rogue
src/cc/rogue/rogue.so
src/cc/rogue/test.zip

View File

@@ -26,6 +26,14 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework):
rpc = self.nodes[0]
rpc1 = self.nodes[1]
# checking channelsaddress call
result = rpc.channelsaddress(self.pubkey)
assert_success(result)
# test that additional CCaddress key is returned
for x in ['myCCaddress', 'ChannelsCCaddress', 'Channelsmarker', 'myaddress', 'CCaddress']:
assert_equal(result[x][0], 'R')
# getting empty channels list
result = rpc.channelslist()
assert_equal(len(result), 2)
@@ -143,7 +151,7 @@ class CryptoconditionsChannelsTest(CryptoconditionsTestFramework):
refund_txid = self.send_and_mine(result["hex"], rpc)
assert refund_txid, "got txid"
# TODO: check if it refunded to opener address
# checking if it refunded to opener address
raw_transaction = rpc.getrawtransaction(refund_txid, 1)
result = raw_transaction["vout"][2]["valueSat"]

View File

@@ -34,21 +34,18 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework):
# getting empty heir list
result = rpc.heirlist()
assert_equal(len(result), 1)
assert_success(result)
assert_equal(result, [])
# valid heirfund case with coins
result = rpc.heirfund("0", "1000", "UNITHEIR", self.pubkey1, "10")
result = rpc.heirfund("0", "1000", "UNITHEIR", self.pubkey1, "10", "TESTMEMO")
assert_success(result)
heir_fund_txid = self.send_and_mine(result["hextx"], rpc)
heir_fund_txid = self.send_and_mine(result["hex"], rpc)
assert heir_fund_txid, "got heir funding txid"
# heir fund txid should be in heirlist now
result = rpc.heirlist()
assert_equal(len(result), 2)
assert_success(result)
assert_equal(result["fundingtxid"], heir_fund_txid)
assert_equal(result, [heir_fund_txid])
# checking heirinfo
result = rpc.heirinfo(heir_fund_txid)
@@ -57,20 +54,20 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework):
assert_equal(result["name"], "UNITHEIR")
assert_equal(result["owner"], self.pubkey)
assert_equal(result["heir"], self.pubkey1)
assert_equal(result["funding total in coins"], "1000.00000000")
assert_equal(result["funding available in coins"], "1000.00000000")
assert_equal(result["inactivity time setting, sec"], "10")
assert_equal(result["spending allowed for the heir"], "false")
# TODO: heirlist keys are duplicating now
assert_equal(result["memo"], "TESTMEMO")
assert_equal(result["lifetime"], "1000.00000000")
assert_equal(result["type"], "coins")
assert_equal(result["InactivityTimeSetting"], "10")
assert_equal(result["InactivityTime"], "0")
assert_equal(result["IsHeirSpendingAllowed"], "false")
# waiting for 11 seconds to be sure that needed time passed for heir claiming
time.sleep(11)
rpc.generate(1)
self.sync_all()
result = rpc.heirinfo(heir_fund_txid)
assert_equal(result["funding available in coins"], "1000.00000000")
assert_equal(result["spending allowed for the heir"], "true")
assert_equal(result["lifetime"], "1000.00000000")
assert_equal(result["IsHeirSpendingAllowed"], "true")
# have to check that second node have coins to cover txfee at least
rpc.sendtoaddress(rpc1.getnewaddress(), 1)
@@ -84,7 +81,7 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework):
result = rpc1.heirclaim("0", "1000", heir_fund_txid)
assert_success(result)
heir_claim_txid = self.send_and_mine(result["hextx"], rpc1)
heir_claim_txid = self.send_and_mine(result["hex"], rpc1)
assert heir_claim_txid, "got claim txid"
# balance of second node after heirclaim should increase for 1000 coins - txfees
@@ -96,9 +93,63 @@ class CryptoconditionsHeirTest(CryptoconditionsTestFramework):
# no more funds should be available for claiming
result = rpc.heirinfo(heir_fund_txid)
assert_equal(result["funding available in coins"], "0.00000000")
assert_equal(result["lifetime"], "1000.00000000")
assert_equal(result["available"], "0.00000000")
# TODO: valid heirfund case with tokens
# creating tokens which we put to heir contract
token_hex = rpc.tokencreate("TEST", "1", "TESTING")
token_txid = self.send_and_mine(token_hex["hex"], rpc)
assert token_txid, "got token txid"
# checking possesion over the tokens and balance
result = rpc.tokenbalance(token_txid, self.pubkey)["balance"]
assert_equal(result, 100000000)
# valid heir case with tokens
token_heir_hex = rpc.heirfund("0", "100000000", "UNITHEIR", self.pubkey1, "10", "TESTMEMO", token_txid)
token_heir_txid = self.send_and_mine(token_heir_hex["hex"], rpc)
assert token_heir_txid, "got txid of heirfund with tokens"
self.sync_all()
# checking heirinfo
result = rpc.heirinfo(token_heir_txid)
assert_success(result)
assert_equal(result["fundingtxid"], token_heir_txid)
assert_equal(result["name"], "UNITHEIR")
assert_equal(result["owner"], self.pubkey)
assert_equal(result["heir"], self.pubkey1)
assert_equal(result["lifetime"], "100000000")
assert_equal(result["type"], "tokens")
assert_equal(result["InactivityTimeSetting"], "10")
assert_equal(result["InactivityTime"], "0")
assert_equal(result["IsHeirSpendingAllowed"], "false")
# waiting for 11 seconds to be sure that needed time passed for heir claiming
time.sleep(11)
rpc.generate(1)
self.sync_all()
result = rpc.heirinfo(token_heir_txid)
assert_equal(result["lifetime"], "100000000")
assert_equal(result["IsHeirSpendingAllowed"], "true")
# let's claim whole heir sum from second node
result = rpc1.heirclaim("0", "100000000", token_heir_txid)
assert_success(result)
heir_tokens_claim_txid = self.send_and_mine(result["hex"], rpc1)
assert heir_tokens_claim_txid, "got claim txid"
# claiming node should have correct token balance now
result = rpc1.tokenbalance(token_txid, self.pubkey1)["balance"]
assert_equal(result, 100000000)
self.sync_all()
# no more funds should be available for claiming
result = rpc.heirinfo(token_heir_txid)
assert_equal(result["lifetime"], "100000000")
assert_equal(result["available"], "0")
def run_test(self):
print("Mining blocks...")

View File

@@ -575,8 +575,14 @@ komodod_LDADD += \
$(LIBBITCOIN_CRYPTO) \
$(LIBVERUS_CRYPTO) \
$(LIBVERUS_PORTABLE_CRYPTO) \
$(LIBZCASH_LIBS) \
libcc.so
$(LIBZCASH_LIBS)
if TARGET_DARWIN
komodod_LDADD += libcc.dylib -lncurses
else
komodod_LDADD += libcc.so -lncurses
endif
if ENABLE_PROTON
komodod_LDADD += $(LIBBITCOIN_PROTON) $(PROTON_LIBS)

View File

@@ -336,6 +336,84 @@ bool CBitcoinAddress::IsScript() const
return IsValid() && vchVersion == Params().Base58Prefix(CChainParams::SCRIPT_ADDRESS);
}
bool CCustomBitcoinAddress::Set(const CKeyID& id)
{
SetData(base58Prefixes[0], &id, 20);
return true;
}
bool CCustomBitcoinAddress::Set(const CPubKey& key)
{
CKeyID id = key.GetID();
SetData(base58Prefixes[0], &id, 20);
return true;
}
bool CCustomBitcoinAddress::Set(const CScriptID& id)
{
SetData(base58Prefixes[1], &id, 20);
return true;
}
bool CCustomBitcoinAddress::Set(const CTxDestination& dest)
{
return boost::apply_visitor(CBitcoinAddressVisitor(this), dest);
}
bool CCustomBitcoinAddress::IsValid() const
{
bool fCorrectSize = vchData.size() == 20;
bool fKnownVersion = vchVersion == base58Prefixes[0] ||
vchVersion == base58Prefixes[1];
return fCorrectSize && fKnownVersion;
}
bool CCustomBitcoinAddress::GetKeyID(CKeyID& keyID) const
{
if (!IsValid() || vchVersion != base58Prefixes[0])
return false;
uint160 id;
memcpy(&id, &vchData[0], 20);
keyID = CKeyID(id);
return true;
}
CTxDestination CCustomBitcoinAddress::Get() const
{
if (!IsValid())
return CNoDestination();
uint160 id;
memcpy(&id, &vchData[0], 20);
if (vchVersion == base58Prefixes[0])
return CKeyID(id);
else if (vchVersion == base58Prefixes[1])
return CScriptID(id);
else
return CNoDestination();
}
bool CCustomBitcoinAddress::GetIndexKey(uint160& hashBytes, int& type) const
{
if (!IsValid()) {
return false;
} else if (vchVersion == base58Prefixes[0]) {
memcpy(&hashBytes, &vchData[0], 20);
type = 1;
return true;
} else if (vchVersion == base58Prefixes[1]) {
memcpy(&hashBytes, &vchData[0], 20);
type = 2;
return true;
}
return false;
}
bool CCustomBitcoinAddress::IsScript() const
{
return IsValid() && vchVersion == base58Prefixes[1];
}
void CBitcoinSecret::SetKey(const CKey& vchSecret)
{
assert(vchSecret.IsValid());

View File

@@ -130,9 +130,9 @@ public:
*/
class CBitcoinAddress : public CBase58Data {
public:
bool Set(const CKeyID &id);
bool Set(const CPubKey &key);
bool Set(const CScriptID &id);
virtual bool Set(const CKeyID &id);
virtual bool Set(const CPubKey &key);
virtual bool Set(const CScriptID &id);
bool Set(const CTxDestination &dest);
bool IsValid() const;
bool IsValid(const CChainParams &params) const;
@@ -151,6 +151,31 @@ public:
bool IsScript() const;
};
class CCustomBitcoinAddress : public CBitcoinAddress {
std::vector<unsigned char> base58Prefixes[2];
public:
bool Set(const CKeyID &id);
bool Set(const CPubKey &key);
bool Set(const CScriptID &id);
bool Set(const CTxDestination &dest);
bool IsValid() const;
CCustomBitcoinAddress() {}
CCustomBitcoinAddress(const CTxDestination &dest,uint8_t taddr,uint8_t pubkey_prefix,uint8_t script_prefix)
{
if (taddr!=0) base58Prefixes[0].push_back(taddr);
base58Prefixes[0].push_back(pubkey_prefix);
base58Prefixes[1].push_back(script_prefix);
Set(dest);
}
CTxDestination Get() const;
bool GetKeyID(CKeyID &keyID) const;
bool GetKeyID_NoCheck(CKeyID& keyID) const;
bool GetIndexKey(uint160& hashBytes, int& type) const;
bool IsScript() const;
};
/**
* A base58-encoded secret key
*/

View File

@@ -21,20 +21,21 @@
#include "../merkleblock.h"
bool GatewaysValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys);
std::string GatewaysBind(uint64_t txfee,std::string coin,uint256 tokenid,int64_t totalsupply,uint256 oracletxid,uint8_t M,uint8_t N,std::vector<CPubKey> pubkeys,uint8_t p1,uint8_t p2,uint8_t p3,uint8_t p4);
std::string GatewaysDeposit(uint64_t txfee,uint256 bindtxid,int32_t height,std::string refcoin,uint256 cointxid,int32_t claimvout,std::string deposithex,std::vector<uint8_t>proof,CPubKey destpub,int64_t amount);
std::string GatewaysClaim(uint64_t txfee,uint256 bindtxid,std::string refcoin,uint256 deposittxid,CPubKey destpub,int64_t amount);
std::string GatewaysWithdraw(uint64_t txfee,uint256 bindtxid,std::string refcoin,CPubKey withdrawpub,int64_t amount);
std::string GatewaysPartialSign(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex);
std::string GatewaysCompleteSigning(uint64_t txfee,uint256 txidaddr,std::string refcoin,std::string hex);
std::string GatewaysMarkDone(uint64_t txfee,uint256 withdrawtxid,std::string refcoin);
UniValue GatewaysPendingDeposits(uint256 bindtxid,std::string refcoin);
UniValue GatewaysPendingWithdraws(uint256 bindtxid,std::string refcoin);
UniValue GatewaysProcessedWithdraws(uint256 bindtxid,std::string refcoin);
UniValue GatewaysMultisig(char *txidaddr);
// CCcustom
UniValue GatewaysInfo(uint256 bindtxid);
UniValue GatewaysExternalAddress(uint256 bindtxid,CPubKey pubkey);
UniValue GatewaysDumpPrivKey(uint256 bindtxid,CKey privkey);
UniValue GatewaysList();
#endif

View File

@@ -27,15 +27,11 @@ bool HeirValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx,
class CoinHelper;
class TokenHelper;
UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid);
UniValue HeirFundCoinCaller(int64_t txfee, int64_t coins, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo);
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid);
UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string amount);
UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string amount);
UniValue HeirInfo(uint256 fundingtxid);
UniValue HeirList();
//std::string Heir_MakeBadTx(uint256 fundingtxid, uint8_t funcId, int64_t amount, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTime, uint32_t errMask);
//bool HeirExactTokenAmounts(bool compareTotals, struct CCcontract_info *cpHeir, Eval* eval, uint256 assetid, const CTransaction &tx);
#endif

View File

@@ -14,8 +14,8 @@
******************************************************************************/
#ifndef CC_TRIGGERS_H
#define CC_TRIGGERS_H
#ifndef CC_MARMARA_H
#define CC_MARMARA_H
#include "CCinclude.h"
#include "../komodo_cJSON.h"
@@ -24,6 +24,7 @@
#define MARMARA_MINLOCK (1440 * 3 * 30)
#define MARMARA_MAXLOCK (1440 * 24 * 30)
#define MARMARA_VINS 16
#define EVAL_MARMARA 0xef
extern uint8_t ASSETCHAINS_MARMARA;
uint64_t komodo_block_prg(uint32_t nHeight);

View File

@@ -29,11 +29,8 @@
bool AssetsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
// CCassetsCore
//CTxOut MakeAssetsVout(CAmount nValue,CPubKey pk);
//CScript EncodeAssetCreateOpRet(uint8_t funcid,std::vector<uint8_t> origpubkey,std::string name,std::string description);
//CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 tokenid, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey);
//bool DecodeAssetCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description);
//uint8_t DecodeAssetOpRet(const CScript &scriptPubKey, uint8_t &evalCode, uint256 &assetid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey);
CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey);
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &assetsEvalCode, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey);
bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CTransaction &tx);
int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid);
bool ValidateBidRemainder(int64_t remaining_price,int64_t remaining_nValue,int64_t orig_nValue,int64_t received_nValue,int64_t paidprice,int64_t totalprice);
@@ -50,7 +47,7 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t
//int64_t GetAssetBalance(CPubKey pk,uint256 tokenid); // --> GetTokenBalance()
int64_t AddAssetInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 assetid, int64_t total, int32_t maxinputs);
UniValue AssetOrders(uint256 tokenid);
UniValue AssetOrders(uint256 tokenid, CPubKey pubkey, uint8_t additionalEvalCode);
//UniValue AssetInfo(uint256 tokenid);
//UniValue AssetList();
//std::string CreateAsset(int64_t txfee,int64_t assetsupply,std::string name,std::string description);

View File

@@ -43,17 +43,17 @@ bool ValidateBidRemainder(int64_t remaining_units,int64_t remaining_nValue,int64
int64_t unitprice,recvunitprice,newunitprice=0;
if ( orig_nValue == 0 || received_nValue == 0 || paidunits == 0 || totalunits == 0 )
{
fprintf(stderr,"ValidateAssetRemainder: orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
fprintf(stderr,"ValidateAssetRemainder() orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
return(false);
}
else if ( totalunits != (remaining_units + paidunits) )
{
fprintf(stderr,"ValidateAssetRemainder: totalunits %llu != %llu (remaining_units %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_units + paidunits),(long long)remaining_units,(long long)paidunits);
fprintf(stderr,"ValidateAssetRemainder() totalunits %llu != %llu (remaining_units %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_units + paidunits),(long long)remaining_units,(long long)paidunits);
return(false);
}
else if ( orig_nValue != (remaining_nValue + received_nValue) )
{
fprintf(stderr,"ValidateAssetRemainder: orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
fprintf(stderr,"ValidateAssetRemainder() orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
return(false);
}
else
@@ -68,10 +68,10 @@ bool ValidateBidRemainder(int64_t remaining_units,int64_t remaining_nValue,int64
newunitprice = (remaining_nValue / remaining_units);
if ( recvunitprice < unitprice )
{
fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
fprintf(stderr,"ValidateAssetRemainder() error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
return(false);
}
fprintf(stderr,"orig %llu total %llu, recv %llu paid %llu,recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(long long)orig_nValue,(long long)totalunits,(long long)received_nValue,(long long)paidunits,(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
fprintf(stderr,"ValidateAssetRemainder() orig %llu total %llu, recv %llu paid %llu,recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(long long)orig_nValue,(long long)totalunits,(long long)received_nValue,(long long)paidunits,(double)recvunitprice/(COIN),(double)unitprice/(COIN),(double)newunitprice/(COIN));
}
return(true);
}
@@ -89,7 +89,7 @@ bool SetBidFillamounts(int64_t &received_nValue,int64_t &remaining_units,int64_t
paidunits = totalunits;
received_nValue = orig_nValue;
remaining_units = 0;
fprintf(stderr,"totally filled!\n");
fprintf(stderr,"SetBidFillamounts() bid order totally filled!\n");
return(true);
}
remaining_units = (totalunits - paidunits);
@@ -100,7 +100,7 @@ bool SetBidFillamounts(int64_t &received_nValue,int64_t &remaining_units,int64_t
if ( unitprice > 0 && received_nValue > 0 && received_nValue <= orig_nValue )
{
remaining_nValue = (orig_nValue - received_nValue);
printf("total.%llu - paid.%llu, remaining %llu <- %llu (%llu - %llu)\n",(long long)totalunits,(long long)paidunits,(long long)remaining_nValue,(long long)(orig_nValue - received_nValue),(long long)orig_nValue,(long long)received_nValue);
printf("SetBidFillamounts() total.%llu - paid.%llu, remaining %llu <- %llu (%llu - %llu)\n",(long long)totalunits,(long long)paidunits,(long long)remaining_nValue,(long long)(orig_nValue - received_nValue),(long long)orig_nValue,(long long)received_nValue);
return(ValidateBidRemainder(remaining_units,remaining_nValue,orig_nValue,received_nValue,paidunits,totalunits));
} else return(false);
}
@@ -118,14 +118,14 @@ bool SetAskFillamounts(int64_t &received_assetoshis,int64_t &remaining_nValue,in
paid_nValue = total_nValue;
received_assetoshis = orig_assetoshis;
remaining_nValue = 0;
fprintf(stderr,"totally filled!\n");
fprintf(stderr,"SetAskFillamounts() ask order totally filled!\n");
return(true);
}
remaining_nValue = (total_nValue - paid_nValue);
dunitprice = ((double)total_nValue / orig_assetoshis);
received_assetoshis = (paid_nValue / dunitprice);
fprintf(stderr,"remaining_nValue %.8f (%.8f - %.8f)\n",(double)remaining_nValue/COIN,(double)total_nValue/COIN,(double)paid_nValue/COIN);
fprintf(stderr,"unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
fprintf(stderr,"SetAskFillamounts() remaining_nValue %.8f (%.8f - %.8f)\n",(double)remaining_nValue/COIN,(double)total_nValue/COIN,(double)paid_nValue/COIN);
fprintf(stderr,"SetAskFillamounts() unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
if ( fabs(dunitprice) > SMALLVAL && received_assetoshis > 0 && received_assetoshis <= orig_assetoshis )
{
remaining_assetoshis = (orig_assetoshis - received_assetoshis);
@@ -138,17 +138,17 @@ bool ValidateAskRemainder(int64_t remaining_nValue,int64_t remaining_assetoshis,
int64_t unitprice,recvunitprice,newunitprice=0;
if ( orig_assetoshis == 0 || received_assetoshis == 0 || paid_nValue == 0 || total_nValue == 0 )
{
fprintf(stderr,"ValidateAssetRemainder: orig_assetoshis == %llu || received_assetoshis == %llu || paid_nValue == %llu || total_nValue == %llu\n",(long long)orig_assetoshis,(long long)received_assetoshis,(long long)paid_nValue,(long long)total_nValue);
fprintf(stderr,"ValidateAssetRemainder() orig_assetoshis == %llu || received_assetoshis == %llu || paid_nValue == %llu || total_nValue == %llu\n",(long long)orig_assetoshis,(long long)received_assetoshis,(long long)paid_nValue,(long long)total_nValue);
return(false);
}
else if ( total_nValue != (remaining_nValue + paid_nValue) )
{
fprintf(stderr,"ValidateAssetRemainder: total_nValue %llu != %llu (remaining_nValue %llu + %llu paid_nValue)\n",(long long)total_nValue,(long long)(remaining_nValue + paid_nValue),(long long)remaining_nValue,(long long)paid_nValue);
fprintf(stderr,"ValidateAssetRemainder() total_nValue %llu != %llu (remaining_nValue %llu + %llu paid_nValue)\n",(long long)total_nValue,(long long)(remaining_nValue + paid_nValue),(long long)remaining_nValue,(long long)paid_nValue);
return(false);
}
else if ( orig_assetoshis != (remaining_assetoshis + received_assetoshis) )
{
fprintf(stderr,"ValidateAssetRemainder: orig_assetoshis %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_assetoshis,(long long)(remaining_assetoshis - received_assetoshis),(long long)remaining_assetoshis,(long long)received_assetoshis);
fprintf(stderr,"ValidateAssetRemainder() orig_assetoshis %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_assetoshis,(long long)(remaining_assetoshis - received_assetoshis),(long long)remaining_assetoshis,(long long)received_assetoshis);
return(false);
}
else
@@ -159,10 +159,10 @@ bool ValidateAskRemainder(int64_t remaining_nValue,int64_t remaining_assetoshis,
newunitprice = (remaining_nValue / remaining_assetoshis);
if ( recvunitprice < unitprice )
{
fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
fprintf(stderr,"ValidateAskRemainder() error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
return(false);
}
fprintf(stderr,"got recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
fprintf(stderr,"ValidateAskRemainder() got recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/COIN,(double)unitprice/COIN,(double)newunitprice/COIN);
}
return(true);
}
@@ -172,7 +172,7 @@ bool SetSwapFillamounts(int64_t &received_assetoshis,int64_t &remaining_assetosh
int64_t remaining_assetoshis; double dunitprice;
if ( total_assetoshis2 == 0 )
{
fprintf(stderr,"total_assetoshis2.0 origsatoshis.%llu paid_assetoshis2.%llu\n",(long long)orig_assetoshis,(long long)paid_assetoshis2);
fprintf(stderr,"SetSwapFillamounts() total_assetoshis2.0 origsatoshis.%llu paid_assetoshis2.%llu\n",(long long)orig_assetoshis,(long long)paid_assetoshis2);
received_assetoshis = remaining_assetoshis2 = paid_assetoshis2 = 0;
return(false);
}
@@ -181,14 +181,14 @@ bool SetSwapFillamounts(int64_t &received_assetoshis,int64_t &remaining_assetosh
paid_assetoshis2 = total_assetoshis2;
received_assetoshis = orig_assetoshis;
remaining_assetoshis2 = 0;
fprintf(stderr,"totally filled!\n");
fprintf(stderr,"SetSwapFillamounts() swap order totally filled!\n");
return(true);
}
remaining_assetoshis2 = (total_assetoshis2 - paid_assetoshis2);
dunitprice = ((double)total_assetoshis2 / orig_assetoshis);
received_assetoshis = (paid_assetoshis2 / dunitprice);
fprintf(stderr,"remaining_assetoshis2 %llu (%llu - %llu)\n",(long long)remaining_assetoshis2/COIN,(long long)total_assetoshis2/COIN,(long long)paid_assetoshis2/COIN);
fprintf(stderr,"unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
fprintf(stderr,"SetSwapFillamounts() remaining_assetoshis2 %llu (%llu - %llu)\n",(long long)remaining_assetoshis2/COIN,(long long)total_assetoshis2/COIN,(long long)paid_assetoshis2/COIN);
fprintf(stderr,"SetSwapFillamounts() unitprice %.8f received_assetoshis %llu orig %llu\n",dunitprice/COIN,(long long)received_assetoshis,(long long)orig_assetoshis);
if ( fabs(dunitprice) > SMALLVAL && received_assetoshis > 0 && received_assetoshis <= orig_assetoshis )
{
remaining_assetoshis = (orig_assetoshis - received_assetoshis);
@@ -201,17 +201,17 @@ bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int6
int64_t unitprice,recvunitprice,newunitprice=0;
if ( orig_nValue == 0 || received_nValue == 0 || paidunits == 0 || totalunits == 0 )
{
fprintf(stderr,"ValidateAssetRemainder: orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
fprintf(stderr,"ValidateAssetRemainder() orig_nValue == %llu || received_nValue == %llu || paidunits == %llu || totalunits == %llu\n",(long long)orig_nValue,(long long)received_nValue,(long long)paidunits,(long long)totalunits);
return(false);
}
else if ( totalunits != (remaining_price + paidunits) )
{
fprintf(stderr,"ValidateAssetRemainder: totalunits %llu != %llu (remaining_price %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_price + paidunits),(long long)remaining_price,(long long)paidunits);
fprintf(stderr,"ValidateAssetRemainder() totalunits %llu != %llu (remaining_price %llu + %llu paidunits)\n",(long long)totalunits,(long long)(remaining_price + paidunits),(long long)remaining_price,(long long)paidunits);
return(false);
}
else if ( orig_nValue != (remaining_nValue + received_nValue) )
{
fprintf(stderr,"ValidateAssetRemainder: orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
fprintf(stderr,"ValidateAssetRemainder() orig_nValue %llu != %llu (remaining_nValue %llu + %llu received_nValue)\n",(long long)orig_nValue,(long long)(remaining_nValue - received_nValue),(long long)remaining_nValue,(long long)received_nValue);
return(false);
}
else
@@ -222,10 +222,10 @@ bool ValidateSwapRemainder(int64_t remaining_price,int64_t remaining_nValue,int6
newunitprice = (remaining_nValue * COIN) / remaining_price;
if ( recvunitprice < unitprice )
{
fprintf(stderr,"error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
fprintf(stderr,"ValidateAssetRemainder() error recvunitprice %.8f < %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
return(false);
}
fprintf(stderr,"recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
fprintf(stderr,"ValidateAssetRemainder() recvunitprice %.8f >= %.8f unitprice, new unitprice %.8f\n",(double)recvunitprice/(COIN*COIN),(double)unitprice/(COIN*COIN),(double)newunitprice/(COIN*COIN));
}
return(true);
}
@@ -279,77 +279,74 @@ bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &o
return(0);
} */
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey)
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &assetsEvalCode, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey)
{
std::vector<uint8_t> vopretExtra, vopretStripped;
uint8_t *script, funcId = 0, assetFuncId = 0, dummyEvalCode, dummyAssetFuncId;
std::vector<uint8_t> vopretAssets; //, vopretAssetsStripped;
uint8_t *script, funcId = 0, assetsFuncId = 0, dummyEvalCode, dummyAssetFuncId;
uint256 dummyTokenid;
std::vector<CPubKey> voutPubkeysDummy;
tokenid = zeroid;
assetid2 = zeroid;
price = 0;
assetsEvalCode = 0;
assetsFuncId = 0;
// First - decode token opret:
funcId = DecodeTokenOpRet(scriptPubKey, evalCodeInOpret, tokenid, voutPubkeysDummy, vopretExtra);
funcId = DecodeTokenOpRet(scriptPubKey, dummyEvalCode, tokenid, voutPubkeysDummy, vopretAssets);
LOGSTREAM((char *)"ccassets", CCLOG_DEBUG2, stream << "DecodeAssetTokenOpRet() from DecodeTokenOpRet returned funcId=" << (int)funcId << std::endl);
/*GetOpReturnData(scriptPubKey, vopret);
script = (uint8_t *)vopret.data();
if (script == 0) {
std::cerr << "DecodeAssetOpRet() script is empty" << std::endl;
return (uint8_t)0;
}*/
//bool isEof = true; // NOTE: if parse error occures, parse might not be able to set error. It is safer to treat that it was eof if it is not set!
//bool result = E_UNMARSHAL(vopret, ss >> evalCodeInOpret; ss >> funcId; ss >> tokenid; ss >> assetFuncId; isEof = ss.eof());
if (funcId == 0 || vopretExtra.size() < 2) {
std::cerr << "DecodeAssetOpRet() incorrect opret or no asset's payload" << " funcId=" << (int)funcId << " vopretExtra.size()=" << vopretExtra.size() << std::endl;
if (funcId == 0 || vopretAssets.size() < 2) {
LOGSTREAM((char *)"ccassets", CCLOG_INFO, stream << "DecodeAssetTokenOpRet() incorrect opret or no asset's payload" << " funcId=" << (int)funcId << " vopretAssets.size()=" << vopretAssets.size() << std::endl);
return (uint8_t)0;
}
if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size
std::cerr << "DecodeAssetTokenOpRet() could not unmarshal vopretStripped" << std::endl;
return (uint8_t)0;
}
//if (!E_UNMARSHAL(vopretAssets, { ss >> vopretAssetsStripped; })) { //strip string size
// std::cerr << "DecodeAssetTokenOpRet() could not unmarshal vopretAssetsStripped" << std::endl;
// return (uint8_t)0;
//}
////tokenid = revuint256(tokenid); already done in DecodeToken!
evalCodeInOpret = vopretStripped.begin()[0];
assetFuncId = vopretStripped.begin()[1];
// additional check to prevent crash
if (vopretAssets.size() >= 2) {
//std::cerr << "DecodeAssetOpRet() evalCodeInOpret=" << (int)evalCodeInOpret << " funcId=" << (char)(funcId ? funcId : ' ') << " assetFuncId=" << (char)(assetFuncId ? assetFuncId : ' ') << std::endl;
assetsEvalCode = vopretAssets.begin()[0];
assetsFuncId = vopretAssets.begin()[1];
if(evalCodeInOpret == EVAL_ASSETS)
{
//fprintf(stderr,"decode.[%c] assetFuncId.[%c]\n", funcId, assetFuncId);
switch( assetFuncId )
LOGSTREAM((char *)"ccassets", CCLOG_DEBUG2, stream << "DecodeAssetTokenOpRet() assetsEvalCode=" << (int)assetsEvalCode << " funcId=" << (char)(funcId ? funcId : ' ') << " assetsFuncId=" << (char)(assetsFuncId ? assetsFuncId : ' ') << std::endl);
if (assetsEvalCode == EVAL_ASSETS)
{
case 'x': case 'o':
if (vopretStripped.size() == 2) // no data after 'evalcode assetFuncId' allowed
//fprintf(stderr,"DecodeAssetTokenOpRet() decode.[%c] assetFuncId.[%c]\n", funcId, assetFuncId);
switch (assetsFuncId)
{
case 'x': case 'o':
if (vopretAssets.size() == 2) // no data after 'evalcode assetFuncId' allowed
{
return(assetFuncId);
return(assetsFuncId);
}
break;
case 's': case 'b': case 'S': case 'B':
if (E_UNMARSHAL(vopretStripped, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0)
if (E_UNMARSHAL(vopretAssets, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> price; ss >> origpubkey) != 0)
{
//fprintf(stderr,"DecodeAssetTokenOpRet got price %llu\n",(long long)price);
return(assetFuncId);
//fprintf(stderr,"DecodeAssetTokenOpRet() got price %llu\n",(long long)price);
return(assetsFuncId);
}
break;
case 'E': case 'e':
if ( E_UNMARSHAL(vopretStripped, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0 )
if (E_UNMARSHAL(vopretAssets, ss >> dummyEvalCode; ss >> dummyAssetFuncId; ss >> assetid2; ss >> price; ss >> origpubkey) != 0)
{
//fprintf(stderr,"DecodeAssetTokenOpRet got price %llu\n",(long long)price);
//fprintf(stderr,"DecodeAssetTokenOpRet() got price %llu\n",(long long)price);
assetid2 = revuint256(assetid2);
return(assetFuncId);
return(assetsFuncId);
}
break;
default:
fprintf(stderr,"DecodeAssetTokenOpRet: illegal assetFuncId.%02x\n", assetFuncId);
//funcId = 0;
break;
}
}
}
LOGSTREAM((char *)"ccassets", CCLOG_INFO, stream << "DecodeAssetTokenOpRet() no asset's payload or incorrect assets funcId or evalcode" << " funcId=" << (int)funcId << " vopretAssets.size()=" << vopretAssets.size() << " assetsEvalCode=" << assetsEvalCode << " assetsFuncId=" << assetsFuncId << std::endl);
return (uint8_t)0;
}
@@ -358,49 +355,53 @@ bool SetAssetOrigpubkey(std::vector<uint8_t> &origpubkey,int64_t &price,const CT
{
uint256 assetid,assetid2;
uint8_t evalCode;
if ( tx.vout.size() > 0 && DecodeAssetTokenOpRet(tx.vout[tx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey) != 0 )
return(true);
else
return(false);
}
// Calculate sell/buy owner's source token/asset address from ask/bid tx
bool GetAssetorigaddrs(struct CCcontract_info *cp, char *userCCaddr, char *destaddr, const CTransaction& tx)
// Calculate seller/buyer's dest cc address from ask/bid tx funcid
bool GetAssetorigaddrs(struct CCcontract_info *cp, char *origCCaddr, char *origNormalAddr, const CTransaction& vintx)
{
uint256 assetid,assetid2; int64_t price,nValue=0; int32_t n; uint8_t funcid;
uint256 assetid, assetid2;
int64_t price,nValue=0;
int32_t n;
uint8_t vintxFuncId;
std::vector<uint8_t> origpubkey;
CScript script;
uint8_t evalCode;
n = tx.vout.size();
if( n == 0 || (funcid = DecodeAssetTokenOpRet(tx.vout[n-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) == 0 )
n = vintx.vout.size();
if( n == 0 || (vintxFuncId = DecodeAssetTokenOpRet(vintx.vout[n-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) == 0 )
return(false);
bool bGetCCaddr = false;
if (funcid == 's' || funcid == 'S') {
struct CCcontract_info *cpTokens, tokensC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
bGetCCaddr = GetCCaddress(cpTokens, userCCaddr, pubkey2pk(origpubkey));
//bGetCCaddr = GetTokensCCaddress(cp, CCaddr, pubkey2pk(origpubkey));
struct CCcontract_info *cpTokens, tokensC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
if (vintxFuncId == 's' || vintxFuncId == 'S') {
// bGetCCaddr = GetCCaddress(cpTokens, origCCaddr, pubkey2pk(origpubkey));
cpTokens->additionalTokensEvalcode2 = cp->additionalTokensEvalcode2; // add non-fungible if present
bGetCCaddr = GetTokensCCaddress(cpTokens, origCCaddr, pubkey2pk(origpubkey)); // tokens to single-eval token or token+nonfungible
}
else if (funcid == 'b' || funcid == 'B') {
struct CCcontract_info *cpTokens, tokensC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
bGetCCaddr = GetCCaddress(cpTokens, userCCaddr, pubkey2pk(origpubkey));
else if (vintxFuncId == 'b' || vintxFuncId == 'B') {
cpTokens->additionalTokensEvalcode2 = cp->additionalTokensEvalcode2; // add non-fungible if present
bGetCCaddr = GetTokensCCaddress(cpTokens, origCCaddr, pubkey2pk(origpubkey)); // tokens to single-eval token or token+nonfungible
}
else {
std::cerr << "GetAssetorigaddrs incorrect funcid=" << (char)(funcid?funcid:' ') << std::endl;
std::cerr << "GetAssetorigaddrs incorrect vintx funcid=" << (char)(vintxFuncId?vintxFuncId:' ') << std::endl;
return false;
}
if( bGetCCaddr && Getscriptaddress(destaddr, CScript() << origpubkey << OP_CHECKSIG))
if( bGetCCaddr && Getscriptaddress(origNormalAddr, CScript() << origpubkey << OP_CHECKSIG))
return(true);
else
return(false);
}
int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx)
int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *origCCaddr,char *origaddr,const CTransaction &tx,int32_t vini,CTransaction &vinTx)
{
uint256 hashBlock;
uint256 assetid, assetid2;
@@ -410,7 +411,7 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch
char destaddr[64], unspendableAddr[64];
origaddr[0] = destaddr[0] = CCaddr[0] = 0;
origaddr[0] = destaddr[0] = origCCaddr[0] = 0;
uint8_t funcid = 0;
if (tx.vout.size() > 0) {
@@ -418,6 +419,7 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch
int64_t tmpprice;
std::vector<uint8_t> tmporigpubkey;
uint8_t evalCode;
funcid = DecodeAssetTokenOpRet(tx.vout[tx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey);
}
@@ -427,45 +429,47 @@ int64_t AssetValidateCCvin(struct CCcontract_info *cp,Eval* eval,char *CCaddr,ch
return eval->Invalid("vin1 needs to be buyvin.vout[0]");
else if( eval->GetTxUnconfirmed(tx.vin[vini].prevout.hash, vinTx,hashBlock) == 0 )
{
/* int32_t z;
for (z=31; z>=0; z--)
fprintf(stderr,"%02x",((uint8_t *)&tx.vin[vini].prevout.hash)[z]);
fprintf(stderr," vini.%d\n",vini); */
std::cerr << "AssetValidateCCvin cannot load vintx for vin=" << vini << " vintx id=" << tx.vin[vini].prevout.hash.GetHex() << std::endl;
std::cerr << "AssetValidateCCvin() cannot load vintx for vin=" << vini << " vintx id=" << tx.vin[vini].prevout.hash.GetHex() << std::endl;
return eval->Invalid("always should find CCvin, but didnt");
}
// if fillSell or cancelSell --> to spend tokens from dual-eval token-assets unspendable addr
// check source cc unspendable cc address:
// if fillSell or cancelSell --> should spend tokens from dual-eval token-assets unspendable addr
else if( (funcid == 'S' || funcid == 'x') &&
(Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ||
!GetTokensCCaddress(cp, unspendableAddr, GetUnspendable(cp, NULL)) ||
strcmp(destaddr, unspendableAddr) != 0))
{
fprintf(stderr,"AssetValidateCCvin cc addr %s is not dual token-evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
return eval->Invalid("invalid vin AssetsCCaddr");
fprintf(stderr,"AssetValidateCCvin() cc addr %s is not dual token-evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
return eval->Invalid("invalid vin assets CCaddr");
}
// if fillBuy or cancelBuy --> to spend coins from asset unspendable addr
// if fillBuy or cancelBuy --> should spend coins from asset unspendable addr
else if ((funcid == 'B' || funcid == 'o') &&
(Getscriptaddress(destaddr, vinTx.vout[tx.vin[vini].prevout.n].scriptPubKey) == 0 ||
!GetCCaddress(cp, unspendableAddr, GetUnspendable(cp, NULL)) ||
strcmp(destaddr, unspendableAddr) != 0))
{
fprintf(stderr, "AssetValidateCCvin cc addr %s is not evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
return eval->Invalid("invalid vin AssetsCCaddr");
fprintf(stderr, "AssetValidateCCvin() cc addr %s is not evalcode=0x%02x asset unspendable addr %s\n", destaddr, (int)cp->evalcode, unspendableAddr);
return eval->Invalid("invalid vin assets CCaddr");
}
// end of check source unspendable cc address
//else if ( vinTx.vout[0].nValue < 10000 )
// return eval->Invalid("invalid dust for buyvin");
else if( GetAssetorigaddrs(cp, CCaddr, origaddr, vinTx) == 0 )
// get user dest cc and normal addresses:
else if( GetAssetorigaddrs(cp, origCCaddr, origaddr, vinTx) == 0 )
return eval->Invalid("couldnt get origaddr for buyvin");
fprintf(stderr,"AssetValidateCCvin got %.8f to origaddr.(%s)\n",(double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr);
//fprintf(stderr,"AssetValidateCCvin() got %.8f to origaddr.(%s)\n", (double)vinTx.vout[tx.vin[vini].prevout.n].nValue/COIN,origaddr);
if ( vinTx.vout[0].nValue == 0 )
return eval->Invalid("null value CCvin");
return(vinTx.vout[0].nValue);
}
int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 refassetid)
{
CTransaction vinTx; int64_t nValue; uint256 assetid,assetid2; uint8_t funcid, evalCode;
CCaddr[0] = origaddr[0] = 0;
// validate locked coins on Assets vin[1]
@@ -473,7 +477,7 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr
return(0);
else if ( vinTx.vout[0].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("invalid normal vout0 for buyvin");
else if ((funcid = DecodeAssetTokenOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' &&
else if ((funcid = DecodeAssetTokenOpRet(vinTx.vout[vinTx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, tmpprice, tmporigpubkey)) == 'b' &&
vinTx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 ) // marker is only in 'b'?
return eval->Invalid("invalid normal vout1 for buyvin");
else
@@ -493,7 +497,7 @@ int64_t AssetValidateBuyvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmppr
int64_t AssetValidateSellvin(struct CCcontract_info *cp,Eval* eval,int64_t &tmpprice,std::vector<uint8_t> &tmporigpubkey,char *CCaddr,char *origaddr,const CTransaction &tx,uint256 assetid)
{
CTransaction vinTx; int64_t nValue,assetoshis;
//fprintf(stderr,"AssetValidateSellvin\n");
//fprintf(stderr,"AssetValidateSellvin()\n");
if ( (nValue = AssetValidateCCvin(cp, eval, CCaddr, origaddr, tx, 1, vinTx)) == 0 )
return(0);
if ( (assetoshis= IsAssetvout(cp, tmpprice, tmporigpubkey, vinTx, 0, assetid)) == 0 )
@@ -514,7 +518,7 @@ bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &pr
if ((funcid = DecodeAssetTokenOpRet(tx.vout[n - 1].scriptPubKey, evalCode, assetidOpret, assetidOpret2, price, origpubkey)) == 0)
{
std::cerr << "ValidateAssetOpret() DecodeAssetTokenOpRet returned null for the opret for txid=" << tx.GetHash().GetHex() << std::endl;
std::cerr << "ValidateAssetOpret() DecodeAssetTokenOpRet returned funcId=0 for opret from txid=" << tx.GetHash().GetHex() << std::endl;
return(false);
}
/* it is now on token level:
@@ -556,22 +560,20 @@ bool ValidateAssetOpret(CTransaction tx, int32_t v, uint256 assetid, int64_t &pr
}
// Checks if the vout is a really Asset CC vout
// compareTotals == true, the func also validates the passed transaction itself:
// it should be either sum(cc vins) == sum(cc vouts) or the transaction is the 'tokenbase' ('c') tx
int64_t IsAssetvout(struct CCcontract_info *cp, int64_t &price, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 refassetid)
{
//std::cerr << "IsAssetvout() entered for txid=" << tx.GetHash().GetHex() << " v=" << v << " for assetid=" << refassetid.GetHex() << std::endl;
int32_t n = tx.vout.size();
// just check boundaries:
if (v >= n - 1) { // just moved this up (dimxy)
std::cerr << "isAssetVout() internal err: (v >= n - 1), returning 0" << std::endl;
return(0);
}
if (tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0) // maybe check address too? dimxy: possibly no, because there are too many cases with different addresses here
{
int32_t n = tx.vout.size();
// just check boundaries:
if (v >= n - 1) { // just moved this up (dimxy)
std::cerr << "isAssetVout() internal err: (v >= n - 1), returning 0" << std::endl;
return(0);
}
// moved opret checking to this new reusable func (dimxy):
const bool valOpret = ValidateAssetOpret(tx, v, refassetid, price, origpubkey);
//std::cerr << "IsAssetvout() ValidateAssetOpret returned=" << std::boolalpha << valOpret << " for txid=" << tx.GetHash().GetHex() << " for assetid=" << refassetid.GetHex() << std::endl;
@@ -620,22 +622,19 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t
assetoshis = IsTokensvout(false, false, cpTokens, NULL, vinTx, tx.vin[i].prevout.n, assetid);
if (assetoshis != 0)
{
std::cerr << "AssetCalcAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl;
//std::cerr << "AssetCalcAmounts() vin i=" << i << " assetoshis=" << assetoshis << std::endl;
inputs += assetoshis;
}
}
}
}
for (int32_t i = 0; i < numvouts; i++)
for (int32_t i = 0; i < numvouts-1; i++)
{
// Note: we pass in here 'false' because we don't need to call AssetExactAmounts() recursively from IsAssetvout
// indeed, in this case we'll be checking this tx again
assetoshis = IsAssetvout(cpAssets, tmpprice, tmporigpubkey, tx, i, assetid);
if (assetoshis != 0)
{
std::cerr << "AssetCalcAmounts() vout i=" << i << " assetoshis=" << assetoshis << std::endl;
//std::cerr << "AssetCalcAmounts() vout i=" << i << " assetoshis=" << assetoshis << std::endl;
outputs += assetoshis;
}
}
@@ -643,12 +642,6 @@ bool AssetCalcAmounts(struct CCcontract_info *cpAssets, int64_t &inputs, int64_t
//std::cerr << "AssetCalcAmounts() inputs=" << inputs << " outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
/* we do not verify inputs == outputs here,
it's done in Tokens:
if (inputs != outputs) {
if (tx.GetHash() != assetid) {
std::cerr << "AssetCalcAmounts() unequal inputs=" << inputs << " vs outputs=" << outputs << " for txid=" << tx.GetHash().GetHex() << std::endl;
return (!eval) ? false : eval->Invalid("assets cc inputs != cc outputs");
}
} */
it's now done in Tokens */
return(true);
}

View File

@@ -14,9 +14,9 @@
******************************************************************************/
#include "CCassets.h"
//#include "CCtokens.h"
#include "CCtokens.h"
/* use AddTokenCCInputs instead
int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs)
{
char coinaddr[64],destaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t j,vout,n = 0;
@@ -47,7 +47,7 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
if( strcmp(destaddr,coinaddr) != 0 && strcmp(destaddr,cp->unspendableCCaddr) != 0 && strcmp(destaddr,cp->unspendableaddr2) != 0 )
continue;
fprintf(stderr,"AddAssetInputs() check destaddress=%s vout amount=%.8f\n",destaddr,(double)vintx.vout[vout].nValue/COIN);
if( (nValue = IsAssetvout(cp, price, origpubkey, vintx, vout, assetid)) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if( (nValue = IsAssetvout(cp, price, origpubkey, vintx, vout, assetid)) > 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -64,124 +64,144 @@ int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
//std::cerr << "AddAssetInputs() found totalinputs=" << totalinputs << std::endl;
return(totalinputs);
}
*/
UniValue AssetOrders(uint256 refassetid)
UniValue AssetOrders(uint256 refassetid, CPubKey pk, uint8_t additionalEvalCode)
{
static uint256 zero;
UniValue result(UniValue::VARR);
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputsTokens, unspentOutputsAssets;
struct CCcontract_info *cpTokens, tokensC;
struct CCcontract_info *cpAssets, assetsC;
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
struct CCcontract_info *cpAssets, assetsC;
struct CCcontract_info *cpTokens, tokensC;
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
auto addOrders = [&](struct CCcontract_info *cp, std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it)
{
uint256 txid, hashBlock, assetid, assetid2;
int64_t price;
std::vector<uint8_t> origpubkey;
CTransaction vintx;
CTransaction ordertx;
uint8_t funcid, evalCode;
char numstr[32], funcidstr[16], origaddr[64], assetidstr[65];
char numstr[32], funcidstr[16], origaddr[64], origtokenaddr[64], assetidstr[65];
txid = it->first.txhash;
//std::cerr << "addOrders() txid=" << txid.GetHex() << std::endl;
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() checking txid=" << txid.GetHex() << std::endl);
if ( GetTransaction(txid, ordertx, hashBlock, false) != 0 )
{
// for logging: funcid = DecodeAssetOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey);
//std::cerr << "addOrders() vintx.vout.size()=" << vintx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << " assetid=" << assetid.GetHex() << std::endl;
if (vintx.vout.size() > 0 && (funcid = DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0)
if (ordertx.vout.size() > 0 && (funcid = DecodeAssetTokenOpRet(ordertx.vout[ordertx.vout.size()-1].scriptPubKey, evalCode, assetid, assetid2, price, origpubkey)) != 0)
{
if (refassetid != zero && assetid != refassetid)
{
//int32_t z;
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&txid)[z]);
//fprintf(stderr," txid\n");
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&assetid)[z]);
//fprintf(stderr," assetid\n");
//for (z=31; z>=0; z--) fprintf(stderr,"%02x",((uint8_t *)&refassetid)[z]);
//fprintf(stderr," refassetid\n");
return;
}
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() checking ordertx.vout.size()=" << ordertx.vout.size() << " funcid=" << (char)(funcid ? funcid : ' ') << " assetid=" << assetid.GetHex() << std::endl);
//std::cerr << "addOrders() it->first.index=" << it->first.index << " vintx.vout[it->first.index].nValue=" << vintx.vout[it->first.index].nValue << std::endl;
if (vintx.vout[it->first.index].nValue == 0)
return;
if (refassetid != zero && assetid == refassetid ||
pk != CPubKey() && pk == pubkey2pk(origpubkey) && (funcid == 'S' || funcid == 's'))
{
UniValue item(UniValue::VOBJ);
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() it->first.index=" << it->first.index << " ordertx.vout[it->first.index].nValue=" << ordertx.vout[it->first.index].nValue << std::endl);
if (ordertx.vout[it->first.index].nValue == 0) {
LOGSTREAM("ccassets", CCLOG_DEBUG2, stream << "addOrders() order with value=0 skipped" << std::endl);
return;
}
funcidstr[0] = funcid;
funcidstr[1] = 0;
item.push_back(Pair("funcid", funcidstr));
item.push_back(Pair("txid", uint256_str(assetidstr,txid)));
item.push_back(Pair("vout", (int64_t)it->first.index));
if ( funcid == 'b' || funcid == 'B' )
{
sprintf(numstr,"%.8f",(double)vintx.vout[it->first.index].nValue/COIN);
item.push_back(Pair("amount",numstr));
sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue/COIN);
item.push_back(Pair("bidamount",numstr));
}
else
{
sprintf(numstr,"%llu",(long long)vintx.vout[it->first.index].nValue);
item.push_back(Pair("amount",numstr));
sprintf(numstr,"%llu",(long long)vintx.vout[0].nValue);
item.push_back(Pair("askamount",numstr));
}
if ( origpubkey.size() == 33 )
{
GetCCaddress(cp, origaddr, pubkey2pk(origpubkey)); // TODO: what is this? is it asset or token??
item.push_back(Pair("origaddress", origaddr));
}
if ( assetid != zeroid )
item.push_back(Pair("tokenid",uint256_str(assetidstr,assetid)));
if ( assetid2 != zeroid )
item.push_back(Pair("otherid",uint256_str(assetidstr,assetid2)));
if ( price > 0 )
{
if ( funcid == 's' || funcid == 'S' || funcid == 'e' || funcid == 'e' )
UniValue item(UniValue::VOBJ);
funcidstr[0] = funcid;
funcidstr[1] = 0;
item.push_back(Pair("funcid", funcidstr));
item.push_back(Pair("txid", uint256_str(assetidstr, txid)));
item.push_back(Pair("vout", (int64_t)it->first.index));
if (funcid == 'b' || funcid == 'B')
{
sprintf(numstr,"%.8f",(double)price / COIN);
item.push_back(Pair("totalrequired", numstr));
sprintf(numstr,"%.8f",(double)price / (COIN * vintx.vout[0].nValue));
item.push_back(Pair("price", numstr));
sprintf(numstr, "%.8f", (double)ordertx.vout[it->first.index].nValue / COIN);
item.push_back(Pair("amount", numstr));
sprintf(numstr, "%.8f", (double)ordertx.vout[0].nValue / COIN);
item.push_back(Pair("bidamount", numstr));
}
else
{
item.push_back(Pair("totalrequired", (int64_t)price));
sprintf(numstr,"%.8f",(double)vintx.vout[0].nValue / (price * COIN));
item.push_back(Pair("price",numstr));
sprintf(numstr, "%llu", (long long)ordertx.vout[it->first.index].nValue);
item.push_back(Pair("amount", numstr));
sprintf(numstr, "%llu", (long long)ordertx.vout[0].nValue);
item.push_back(Pair("askamount", numstr));
}
if (origpubkey.size() == 33)
{
GetCCaddress(cp, origaddr, pubkey2pk(origpubkey));
item.push_back(Pair("origaddress", origaddr));
GetTokensCCaddress(cpTokens, origtokenaddr, pubkey2pk(origpubkey));
item.push_back(Pair("origtokenaddress", origtokenaddr));
}
if (assetid != zeroid)
item.push_back(Pair("tokenid", uint256_str(assetidstr, assetid)));
if (assetid2 != zeroid)
item.push_back(Pair("otherid", uint256_str(assetidstr, assetid2)));
if (price > 0)
{
if (funcid == 's' || funcid == 'S' || funcid == 'e' || funcid == 'e')
{
sprintf(numstr, "%.8f", (double)price / COIN);
item.push_back(Pair("totalrequired", numstr));
sprintf(numstr, "%.8f", (double)price / (COIN * ordertx.vout[0].nValue));
item.push_back(Pair("price", numstr));
}
else
{
item.push_back(Pair("totalrequired", (int64_t)price));
sprintf(numstr, "%.8f", (double)ordertx.vout[0].nValue / (price * COIN));
item.push_back(Pair("price", numstr));
}
}
result.push_back(item);
LOGSTREAM("ccassets", CCLOG_DEBUG1, stream << "addOrders() added order funcId=" << (char)(funcid ? funcid : ' ') << " it->first.index=" << it->first.index << " ordertx.vout[it->first.index].nValue=" << ordertx.vout[it->first.index].nValue << " tokenid=" << assetid.GetHex() << std::endl);
}
result.push_back(item);
//fprintf(stderr,"addOrders() func.(%c) %s/v%d %.8f\n",funcid,uint256_str(assetidstr,txid),(int32_t)it->first.index,(double)vintx.vout[it->first.index].nValue/COIN);
}
}
};
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputsTokens, unspentOutputsDualEvalTokens, unspentOutputsCoins;
char assetsUnspendableAddr[64];
GetCCaddress(cpAssets, assetsUnspendableAddr, GetUnspendable(cpAssets, NULL));
SetCCunspents(unspentOutputsAssets, assetsUnspendableAddr /*(char *)cpTokens->unspendableCCaddr*/);
SetCCunspents(unspentOutputsCoins, assetsUnspendableAddr);
char tokensUnspendableAddr[64];
GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
SetCCunspents(unspentOutputsAssets, tokensUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/);
char assetsTokensUnspendableAddr[64];
std::vector<uint8_t> vopretNonfungible;
if (refassetid != zeroid) {
GetNonfungibleData(refassetid, vopretNonfungible);
if (vopretNonfungible.size() > 0)
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
}
GetTokensCCaddress(cpAssets, assetsTokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
SetCCunspents(unspentOutputsTokens, assetsTokensUnspendableAddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itTokens = unspentOutputsTokens.begin();
// tokenbids:
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itCoins = unspentOutputsCoins.begin();
itCoins != unspentOutputsCoins.end();
itCoins++)
addOrders(cpAssets, itCoins);
// tokenasks:
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itTokens = unspentOutputsTokens.begin();
itTokens != unspentOutputsTokens.end();
itTokens++)
addOrders(cpTokens, itTokens);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itAssets = unspentOutputsAssets.begin();
itAssets != unspentOutputsAssets.end();
itAssets++)
addOrders(cpAssets, itAssets);
addOrders(cpAssets, itTokens);
if (additionalEvalCode != 0) { //this would be mytokenorders
char assetsDualEvalTokensUnspendableAddr[64];
// try also dual eval tokenasks (and we do not need bids):
cpAssets->additionalTokensEvalcode2 = additionalEvalCode;
GetTokensCCaddress(cpAssets, assetsDualEvalTokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
SetCCunspents(unspentOutputsDualEvalTokens, assetsDualEvalTokensUnspendableAddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator itDualEvalTokens = unspentOutputsDualEvalTokens.begin();
itDualEvalTokens != unspentOutputsDualEvalTokens.end();
itDualEvalTokens++)
addOrders(cpAssets, itDualEvalTokens);
}
return(result);
}
@@ -328,14 +348,14 @@ std::string CreateBuyOffer(int64_t txfee, int64_t bidamount, uint256 assetid, in
return ("");
}
CPubKey unspendablePubkey = GetUnspendable(cpAssets, 0);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, unspendablePubkey));
CPubKey unspendableAssetsPubkey = GetUnspendable(cpAssets, 0);
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount, unspendableAssetsPubkey));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk));
std::vector<CPubKey> voutTokenPubkeys; // should be empty - no token vouts
return(FinalizeCCTx(0, cpAssets, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('b', zeroid, pricetotal, Mypubkey()))));
EncodeTokenOpRet(assetid, voutTokenPubkeys, // TODO: actually this tx is not 'tokens', maybe it is better not to have token opret here but only asset opret.
EncodeAssetOpRet('b', zeroid, pricetotal, Mypubkey())))); // But still such token opret should not make problems because no token eval in these vouts
}
CCerror = strprintf("no coins found to make buy offer");
return("");
@@ -348,7 +368,6 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
CPubKey mypk;
uint64_t mask;
int64_t inputs, CCchange;
CScript opret;
struct CCcontract_info *cpAssets, assetsC;
struct CCcontract_info *cpTokens, tokensC;
@@ -359,7 +378,8 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
return("");
}
cpAssets = CCinit(&assetsC, EVAL_ASSETS); // NOTE: this is for signing
cpAssets = CCinit(&assetsC, EVAL_ASSETS); // NOTE: for signing
if (txfee == 0)
txfee = 10000;
@@ -367,10 +387,11 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
mypk = pubkey2pk(Mypubkey());
if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
{
std::vector<uint8_t> vopretNonfungible;
mask = ~((1LL << mtx.vin.size()) - 1);
// add single-eval tokens:
cpTokens = CCinit(&tokensC, EVAL_TOKENS); // NOTE: tokens is here
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, askamount, 60)) > 0)
// add single-eval tokens (or non-fungible tokens):
cpTokens = CCinit(&tokensC, EVAL_TOKENS); // NOTE: adding inputs only from EVAL_TOKENS cc
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, askamount, 60, vopretNonfungible)) > 0)
{
if (inputs < askamount) {
//was: askamount = inputs;
@@ -379,20 +400,26 @@ std::string CreateSell(int64_t txfee,int64_t askamount,uint256 assetid,int64_t p
return ("");
}
CPubKey unspendablePubkey = GetUnspendable(cpAssets, NULL);
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, askamount, unspendablePubkey));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); //marker
// if this is non-fungible tokens:
if( !vopretNonfungible.empty() )
// set its evalcode
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
CPubKey unspendableAssetsPubkey = GetUnspendable(cpAssets, NULL);
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, cpAssets->additionalTokensEvalcode2, askamount, unspendableAssetsPubkey));
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, mypk)); //marker (seems, it is not for tokenorders)
if (inputs > askamount)
CCchange = (inputs - askamount);
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // change to single-eval token vout
// change to single-eval or non-fungible token vout (although for non-fungible token change currently is not possible)
mtx.vout.push_back(MakeTokensCC1vout((cpAssets->additionalTokensEvalcode2) ? cpAssets->additionalTokensEvalcode2 : EVAL_TOKENS, CCchange, mypk));
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(unspendablePubkey);
voutTokenPubkeys.push_back(unspendableAssetsPubkey);
opret = EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey()));
return(FinalizeCCTx(mask,cpAssets, mtx, mypk, txfee, opret));
return FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('s', zeroid, pricetotal, Mypubkey())));
}
else {
fprintf(stderr, "need some tokens to place ask\n");
@@ -430,7 +457,7 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a
if (AddNormalinputs(mtx, mypk, txfee, 3) > 0)
{
mask = ~((1LL << mtx.vin.size()) - 1);
if ((inputs = AddAssetInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0)
/*if ((inputs = AddAssetInputs(cp, mtx, mypk, assetid, askamount, 60)) > 0)
{
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
if (inputs < askamount) {
@@ -458,13 +485,13 @@ std::string CreateSwap(int64_t txfee,int64_t askamount,uint256 assetid,uint256 a
else {
opret = EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('e', assetid2, pricetotal, Mypubkey()));
}
}
////////////////////////// NOT IMPLEMENTED YET/////////////////////////////////
return(FinalizeCCTx(mask,cp,mtx,mypk,txfee,opret));
}
else {
fprintf(stderr, "need some assets to place ask\n");
}
} */
}
else { // dimxy added 'else', because it was misleading message before
fprintf(stderr,"need some native coins to place ask\n");
@@ -494,12 +521,14 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
mask = ~((1LL << mtx.vin.size()) - 1);
if (GetTransaction(bidtxid, vintx, hashBlock, false) != 0)
{
std::vector<uint8_t> vopretNonfungible;
GetNonfungibleData(assetid, vopretNonfungible);
bidamount = vintx.vout[0].nValue;
mtx.vin.push_back(CTxIn(bidtxid, 0, CScript())); // coins in Assets
if((funcid=DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey))!=0)
{
if (funcid == 's') mtx.vin.push_back(CTxIn(bidtxid, 1, CScript())); // spend marker if funcid='b'
else if (funcid=='S') mtx.vin.push_back(CTxIn(bidtxid, 3, CScript())); // spend marker if funcid='B'
}
@@ -510,8 +539,8 @@ std::string CancelBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid)
std::vector<CPubKey> voutTokenPubkeys; // should be empty, no token vouts
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('o', zeroid, 0, Mypubkey()))));
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('o', zeroid, 0, Mypubkey()))));
}
}
return("");
@@ -523,8 +552,12 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction vintx; uint64_t mask;
uint256 hashBlock; int64_t askamount;
CPubKey mypk; struct CCcontract_info *cpTokens, *cpAssets, tokensC, assetsC;
uint8_t funcid,dummyEvalCode; uint256 dummyAssetid, dummyAssetid2; int64_t dummyPrice; std::vector<uint8_t> dummyOrigpubkey;
CPubKey mypk;
struct CCcontract_info *cpTokens, *cpAssets, tokensC, assetsC;
uint8_t funcid, dummyEvalCode;
uint256 dummyAssetid, dummyAssetid2;
int64_t dummyPrice;
std::vector<uint8_t> dummyOrigpubkey;
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
@@ -538,27 +571,29 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
mask = ~((1LL << mtx.vin.size()) - 1);
if (GetTransaction(asktxid, vintx, hashBlock, false) != 0)
{
std::vector<uint8_t> vopretNonfungible;
GetNonfungibleData(assetid, vopretNonfungible);
askamount = vintx.vout[0].nValue;
mtx.vin.push_back(CTxIn(asktxid, 0, CScript()));
if ((funcid=DecodeAssetTokenOpRet(vintx.vout[vintx.vout.size() - 1].scriptPubKey, dummyEvalCode, dummyAssetid, dummyAssetid2, dummyPrice, dummyOrigpubkey))!=0)
{
if (funcid == 's') mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s'
else if (funcid=='S') mtx.vin.push_back(CTxIn(asktxid, 3, CScript())); // marker if funcid='S'
if (funcid == 's')
mtx.vin.push_back(CTxIn(asktxid, 1, CScript())); // marker if funcid='s'
else if (funcid=='S')
mtx.vin.push_back(CTxIn(asktxid, 3, CScript())); // marker if funcid='S'
}
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, askamount, mypk)); // one-eval token vout
if (vopretNonfungible.size() > 0)
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
mtx.vout.push_back(MakeTokensCC1vout(cpAssets->additionalTokensEvalcode2 == 0 ? EVAL_TOKENS : cpAssets->additionalTokensEvalcode2, askamount, mypk)); // one-eval token vout
mtx.vout.push_back(CTxOut(txfee,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(mypk);
/* char myCCaddr[65];
uint8_t myPrivkey[32];
Myprivkey(myPrivkey);
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
GetCCaddress(cpAssets, myCCaddr, mypk); */
// this is only for unspendable addresses:
//CCaddr2set(cpTokens, EVAL_ASSETS, mypk, myPrivkey, myCCaddr); //do we need this? Seems FinalizeCCTx can attach to any evalcode cc addr by calling Getscriptaddress
@@ -572,7 +607,7 @@ std::string CancelSell(int64_t txfee,uint256 assetid,uint256 asktxid)
CCaddr2set(cpAssets, EVAL_TOKENS, unspendableAssetsPk, unspendableAssetsPrivkey, unspendableAssetsAddr);
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('x', zeroid, 0, Mypubkey()))));
}
}
@@ -614,8 +649,9 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
SetAssetOrigpubkey(origpubkey, origprice, vintx);
mtx.vin.push_back(CTxIn(bidtxid, bidvout, CScript())); // Coins on Assets unspendable
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, fillamount, 60)) > 0)
std::vector<uint8_t> vopretNonfungible;
if ((inputs = AddTokenCCInputs(cpTokens, mtx, mypk, assetid, fillamount, 60, vopretNonfungible)) > 0)
{
if (inputs < fillamount) {
std::cerr << "FillBuyOffer(): insufficient tokens to fill buy offer" << std::endl;
@@ -624,6 +660,10 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
}
SetBidFillamounts(paid_amount, remaining_required, bidamount, fillamount, origprice);
uint8_t additionalTokensEvalcode2 = 0;
if (vopretNonfungible.size() > 0)
additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
if (inputs > fillamount)
CCchange = (inputs - fillamount);
@@ -634,13 +674,13 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, bidamount - paid_amount, unspendableAssetsPk)); // vout0 coins remainder
mtx.vout.push_back(CTxOut(paid_amount,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG)); // vout1 coins to normal
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens sent to the buyer
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS,txfee,origpubkey)); // vout3 marker to origpubkey
mtx.vout.push_back(MakeTokensCC1vout(additionalTokensEvalcode2 == 0 ? EVAL_TOKENS : additionalTokensEvalcode2, fillamount, pubkey2pk(origpubkey))); // vout2 single-eval tokens sent to the originator
mtx.vout.push_back(MakeCC1vout(EVAL_ASSETS, txfee, origpubkey)); // vout3 marker to origpubkey
if (CCchange != 0)
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, CCchange, mypk)); // vout4 change in single-eval tokens
fprintf(stderr,"FillBuyOffer remaining %llu -> origpubkey\n", (long long)remaining_required);
fprintf(stderr,"FillBuyOffer() remaining %llu -> origpubkey\n", (long long)remaining_required);
char unspendableAssetsAddr[64];
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
@@ -653,8 +693,8 @@ std::string FillBuyOffer(int64_t txfee,uint256 assetid,uint256 bidtxid,int64_t f
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(pubkey2pk(origpubkey));
return(FinalizeCCTx(mask,cpTokens,mtx,mypk,txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
return(FinalizeCCTx(mask, cpTokens, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet('B', zeroid, remaining_required, origpubkey))));
} else return("dont have any assets to fill bid");
}
@@ -691,15 +731,21 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
return("");
}
std::vector<uint8_t> vopretNonfungible;
uint8_t additionalTokensEvalcode2 = 0;
GetNonfungibleData(assetid, vopretNonfungible);
if (vopretNonfungible.size() > 0)
additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
cpAssets = CCinit(&assetsC, EVAL_ASSETS);
if (txfee == 0)
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
{
mask = ~((1LL << mtx.vin.size()) - 1);
//if (AddNormalinputs(mtx, mypk, 2*txfee, 3) > 0)
//{
//mask = ~((1LL << mtx.vin.size()) - 1);
if (GetTransaction(asktxid, vintx, hashBlock, false) != 0)
{
orig_assetoshis = vintx.vout[askvout].nValue;
@@ -707,13 +753,12 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
dprice = (double)total_nValue / orig_assetoshis;
paid_nValue = dprice * fillunits;
mtx.vin.push_back(CTxIn(asktxid, askvout, CScript())); // NOTE: this is the reference to tokens -> send cpTokens for signing into FinalizeCCTx!
if (assetid2 != zeroid)
inputs = AddAssetInputs(cpAssets, mtx, mypk, assetid2, paid_nValue, 60); // not implemented yet
if (assetid2 != zeroid) {
inputs = 0; // = AddAssetInputs(cpAssets, mtx, mypk, assetid2, paid_nValue, 60); // not implemented yet
}
else
{
inputs = AddNormalinputs(mtx, mypk, paid_nValue, 60);
inputs = AddNormalinputs(mtx, mypk, 2 * txfee + paid_nValue, 60); // Better to use single AddNormalinputs() to allow payment if user has only single utxo with normal funds
mask = ~((1LL << mtx.vin.size()) - 1);
}
if (inputs > 0)
@@ -723,7 +768,10 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
CCerror = strprintf("insufficient coins to fill sell");
return ("");
}
// cc vin should be after normal vin
mtx.vin.push_back(CTxIn(asktxid, askvout, CScript()));
if (assetid2 != zeroid)
SetSwapFillamounts(received_assetoshis, remaining_nValue, orig_assetoshis, paid_nValue, total_nValue); //not implemented correctly yet
else
@@ -732,11 +780,11 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
if (assetid2 != zeroid && inputs > paid_nValue)
CCchange = (inputs - paid_nValue);
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL))); // vout.0 tokens remainder to unspendable cc addr
mtx.vout.push_back(MakeCC1vout(EVAL_TOKENS, received_assetoshis, mypk)); //vout.1 purchased tokens to self single-eval addr
// vout.0 tokens remainder to unspendable cc addr:
mtx.vout.push_back(MakeTokensCC1vout(EVAL_ASSETS, additionalTokensEvalcode2, orig_assetoshis - received_assetoshis, GetUnspendable(cpAssets, NULL)));
//vout.1 purchased tokens to self token single-eval or dual-eval token+nonfungible cc addr:
mtx.vout.push_back(MakeTokensCC1vout(additionalTokensEvalcode2 == 0 ? EVAL_TOKENS : additionalTokensEvalcode2, received_assetoshis, mypk));
// NOTE: no marker here
if (assetid2 != zeroid) {
std::cerr << "FillSell() WARNING: asset swap not implemented yet! (paid_nValue)" << std::endl;
// TODO: change MakeCC1vout appropriately when implementing:
@@ -768,14 +816,16 @@ std::string FillSell(int64_t txfee, uint256 assetid, uint256 assetid2, uint256 a
std::vector<CPubKey> voutTokenPubkeys;
voutTokenPubkeys.push_back(mypk);
cpAssets->additionalTokensEvalcode2 = additionalTokensEvalcode2;
return(FinalizeCCTx(mask, cpAssets, mtx, mypk, txfee,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeTokenOpRet(assetid, voutTokenPubkeys,
EncodeAssetOpRet(assetid2 != zeroid ? 'E' : 'S', assetid2, remaining_nValue, origpubkey))));
} else {
CCerror = strprintf("filltx not enough utxos");
fprintf(stderr,"%s\n", CCerror.c_str());
}
}
}
//}
return("");
}

View File

@@ -245,26 +245,54 @@ uint8_t CClibCCpriv[32] = { 0x57, 0xcf, 0x49, 0x71, 0x7d, 0xb4, 0x15, 0x1b, 0x4f
int32_t CClib_initcp(struct CCcontract_info *cp,uint8_t evalcode)
{
CPubKey pk; uint8_t pub33[33]; char CCaddr[64];
CPubKey pk; int32_t i; uint8_t pub33[33],check33[33],hash[32]; char CCaddr[64],checkaddr[64],str[67];
cp->evalcode = evalcode;
cp->ismyvin = IsCClibInput;
memcpy(cp->CCpriv,CClibCCpriv,32);
if ( evalcode == EVAL_FIRSTUSER ) // eventually make a hashchain for each evalcode
{
cp->evalcode = evalcode;
cp->ismyvin = IsCClibInput;
strcpy(cp->CChexstr,CClibCChexstr);
memcpy(cp->CCpriv,CClibCCpriv,32);
decode_hex(pub33,33,cp->CChexstr);
pk = buf2pk(pub33);
Getscriptaddress(cp->normaladdr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG);
if ( strcmp(cp->normaladdr,CClibNormaladdr) != 0 )
fprintf(stderr,"CClib_initcp addr mismatch %s vs %s\n",cp->normaladdr,CClibNormaladdr);
GetCCaddress(cp,cp->unspendableCCaddr,pk);
return(0);
if ( priv2addr(checkaddr,check33,cp->CCpriv) != 0 )
{
if ( buf2pk(check33) == pk && strcmp(checkaddr,cp->normaladdr) == 0 )
{
//fprintf(stderr,"verified evalcode.%d %s %s\n",cp->evalcode,checkaddr,pubkey33_str(str,pub33));
return(0);
} else fprintf(stderr,"CClib_initcp mismatched privkey -> addr %s vs %s\n",checkaddr,cp->normaladdr);
}
}
else
{
for (i=EVAL_FIRSTUSER; i<evalcode; i++)
{
vcalc_sha256(0,hash,cp->CCpriv,32);
memcpy(cp->CCpriv,hash,32);
}
if ( priv2addr(cp->normaladdr,pub33,cp->CCpriv) != 0 )
{
pk = buf2pk(pub33);
for (i=0; i<33; i++)
sprintf(&cp->CChexstr[i*2],"%02x",pub33[i]);
cp->CChexstr[i*2] = 0;
GetCCaddress(cp,cp->unspendableCCaddr,pk);
//printf("evalcode.%d initialized\n",evalcode);
return(0);
}
}
return(-1);
}
struct CCcontract_info *CCinit(struct CCcontract_info *cp, uint8_t evalcode)
{
// important to clear because not all members are always initialized!
memset(cp, '\0', sizeof(*cp));
cp->evalcode = evalcode;
switch ( evalcode )
{

View File

@@ -42,6 +42,7 @@ one other technical note is that komodod has the insight-explorer extensions bui
#include <cryptoconditions.h>
#include "../script/standard.h"
#include "../base58.h"
#include "../key.h"
#include "../core_io.h"
#include "../script/sign.h"
#include "../wallet/wallet.h"
@@ -51,7 +52,7 @@ one other technical note is that komodod has the insight-explorer extensions bui
#include "../utlist.h"
#include "../uthash.h"
#define CC_BURNPUBKEY "02deaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddeaddead"
#define CC_MAXVINS 1024
#define SMALLVAL 0.000000000000001
@@ -66,6 +67,12 @@ one other technical note is that komodod has the insight-explorer extensions bui
#include "../komodo_cJSON.h"
// opret data block ids:
enum {
OPRETID_NONFUNGIBLEDATA = 0x11
// TODO: OPRETID_ASSETSDATA = 0x12
};
struct CC_utxo
{
uint256 txid;
@@ -88,13 +95,14 @@ struct CCcontract_info
{
// this is for spending from 'unspendable' CC address
uint8_t evalcode;
uint8_t additionalTokensEvalcode2; // this is for making three-eval-token vouts (EVAL_TOKENS + evalcode + additionalEvalcode2)
char unspendableCCaddr[64], CChexstr[72], normaladdr[64];
uint8_t CCpriv[32];
// this for 1of2 keys coins cryptocondition (for this evalcode)
// NOTE: only one evalcode is allowed at this time
char coins1of2addr[64];
CPubKey coins1of2pk[2];
CPubKey coins1of2pk[2]; uint8_t coins1of2priv[32];
// the same for tokens 1of2 keys cc
char tokens1of2addr[64];
@@ -102,7 +110,7 @@ struct CCcontract_info
// this is for spending from two additional 'unspendable' CC addresses of other eval codes
// (that is, for spending from several cc contract 'unspendable' addresses):
uint8_t evalcode2, evalcode3;
uint8_t unspendableEvalcode2, unspendableEvalcode3; // changed evalcodeN to unspendableEvalcodeN for not mixing up with additionalEvalcodeN
char unspendableaddr2[64], unspendableaddr3[64];
uint8_t unspendablepriv2[32], unspendablepriv3[32];
CPubKey unspendablepk2, unspendablepk3;
@@ -133,13 +141,18 @@ int32_t CCgetspenttxid(uint256 &spenttxid,int32_t &vini,int32_t &height,uint256
void CCclearvars(struct CCcontract_info *cp);
UniValue CClib(struct CCcontract_info *cp,char *method,cJSON *params);
UniValue CClib_info(struct CCcontract_info *cp);
CBlockIndex *komodo_blockindex(uint256 hash);
CBlockIndex *komodo_chainactive(int32_t height);
int32_t komodo_blockheight(uint256 hash);
static const uint256 zeroid;
static uint256 ignoretxid;
static int32_t ignorevin;
bool myGetTransaction(const uint256 &hash, CTransaction &txOut, uint256 &hashBlock);
int32_t is_hexstr(char *str,int32_t n);
bool myAddtomempool(CTransaction &tx, CValidationState *pstate = NULL, bool fSkipExpiry = false);
int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag);
bool myIsutxo_spentinmempool(uint256 txid,int32_t vout);
bool myIsutxo_spentinmempool(uint256 &spenttxid,int32_t &spentvini,uint256 txid,int32_t vout);
bool mytxid_inmempool(uint256 txid);
int32_t myIsutxo_spent(uint256 &spenttxid,uint256 txid,int32_t vout);
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
@@ -148,6 +161,7 @@ int32_t iguana_rwbignum(int32_t rwflag,uint8_t *serialized,int32_t len,uint8_t *
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
int64_t CCaddress_balance(char *coinaddr);
CPubKey CCtxidaddr(char *txidaddr,uint256 txid);
CPubKey CCCustomtxidaddr(char *txidaddr,uint256 txid,uint8_t taddr,uint8_t prefix,uint8_t prefix2);
bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn,
CTransaction &txOut, std::vector<std::vector<unsigned char>> &preConditions, std::vector<std::vector<unsigned char>> &params);
@@ -158,17 +172,18 @@ uint256 OraclesBatontxid(uint256 oracletxid,CPubKey pk);
//int64_t AddAssetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,uint256 assetid,int64_t total,int32_t maxinputs);
int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs);
int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs, std::vector<uint8_t> &vopretNonfungible);
int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, int32_t v, uint256 reftokenid);
bool DecodeHexTx(CTransaction& tx, const std::string& strHexTx);
CScript EncodeAssetOpRet(uint8_t assetFuncId, uint256 assetid2, int64_t price, std::vector<uint8_t> origpubkey);
//bool DecodeAssetCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description);
uint8_t DecodeAssetTokenOpRet(const CScript &scriptPubKey, uint8_t &evalCodeInOpret, uint256 &tokenid, uint256 &assetid2, int64_t &price, std::vector<uint8_t> &origpubkey);
CScript EncodeTokenCreateOpRet(uint8_t funcid, std::vector<uint8_t> origpubkey, std::string name, std::string description, std::vector<uint8_t> vopretNonfungible);
CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload); //old version
CScript EncodeTokenOpRet(uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload);
CScript EncodeTokenOpRet(uint8_t tokenFuncId, uint8_t evalCodeInOpret, uint256 tokenid, std::vector<CPubKey> voutPubkeys, CScript payload);
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description);
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCode, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopretExtra);
uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey, std::vector<uint8_t> &origpubkey, std::string &name, std::string &description, std::vector<uint8_t> &vopretNonfungible);
uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopretExtra);
void GetNonfungibleData(uint256 tokenid, std::vector<uint8_t> &vopretNonfungible);
uint8_t DecodeOraclesData(const CScript &scriptPubKey,uint256 &oracletxid,uint256 &batontxid,CPubKey &pk,std::vector <uint8_t>&data);
int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t *data,int32_t offset,int32_t datalen);
@@ -177,8 +192,10 @@ int32_t oracle_format(uint256 *hashp,int64_t *valp,char *str,uint8_t fmt,uint8_t
// CCcustom
CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv);
//uint8_t DecodeTokenOpRet(const CScript scriptPubKey, uint8_t &evalCodeTokens, uint256 &tokenid, std::vector<CPubKey> &voutPubkeys, std::vector<uint8_t> &vopret1, std::vector<uint8_t> &vopret2);
// CCutils
bool priv2addr(char *coinaddr,uint8_t buf33[33],uint8_t priv32[32]);
CPubKey buf2pk(uint8_t *buf33);
void endiancpy(uint8_t *dest,uint8_t *src,int32_t len);
uint256 DiceHashEntropy(uint256 &entropy,uint256 _txidpriv,int32_t entropyvout,int32_t usevout);
@@ -189,13 +206,15 @@ CC *MakeCCcond1of2(uint8_t evalcode,CPubKey pk1,CPubKey pk2);
CC* GetCryptoCondition(CScript const& scriptSig);
void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr);
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr);
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2,uint8_t *priv,char *coinaddr);
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2);
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk1, CPubKey pk2);
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk);
CTxOut MakeTokensCC1vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk);
CC *MakeTokensCCcond1of2(uint8_t evalcode, uint8_t evalcode2, CPubKey pk1, CPubKey pk2);
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2);
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk);
CC *MakeTokensCCcond1(uint8_t evalcode, uint8_t evalcode2, CPubKey pk);
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk);
bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2);
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr);
@@ -219,6 +238,7 @@ bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubK
bool ConstrainVout(CTxOut vout,int32_t CCflag,char *cmpaddr,int64_t nValue);
bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t numvins,int32_t preventCCvouts,int32_t numvouts);
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey);
bool GetCustomscriptaddress(char *destaddr,const CScript &scriptPubKey,uint8_t taddr,uint8_t prefix,uint8_t prefix2);
std::vector<uint8_t> Mypubkey();
bool Myprivkey(uint8_t myprivkey[]);
int64_t CCduration(int32_t &numblocks,uint256 txid);
@@ -242,4 +262,31 @@ void vcalc_sha256(char deprecated[(256 >> 3) * 2 + 1],uint8_t hash[256 >> 3],uin
bits256 bits256_doublesha256(char *deprecated,uint8_t *data,int32_t datalen);
UniValue ValueFromAmount(const CAmount& amount);
// bitcoin LogPrintStr with category "-debug" cmdarg support for C++ ostringstream:
#define CCLOG_INFO 0
#define CCLOG_DEBUG1 1
#define CCLOG_DEBUG2 2
#define CCLOG_DEBUG3 3
#define CCLOG_MAXLEVEL 3
template <class T>
void CCLogPrintStream(const char *category, int level, T print_to_stream)
{
std::ostringstream stream;
print_to_stream(stream);
if (level < 0)
level = 0;
if (level > CCLOG_MAXLEVEL)
level = CCLOG_MAXLEVEL;
for (int i = level; i <= CCLOG_MAXLEVEL; i++)
if( LogAcceptCategory((std::string(category) + std::string("-") + std::to_string(i)).c_str()) || // '-debug=cctokens-0', '-debug=cctokens-1',...
i == 0 && LogAcceptCategory(std::string(category).c_str()) ) { // also supporting '-debug=cctokens' for CCLOG_INFO
LogPrintStr(stream.str());
break;
}
}
// use: LOGSTREAM("yourcategory", your-debug-level, stream << "some log data" << data2 << data3 << ... << std::endl);
#define LOGSTREAM(category, level, logoperator) CCLogPrintStream( category, level, [=](std::ostringstream &stream) {logoperator;} )
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -28,17 +28,13 @@
// CCcustom
bool TokensValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn);
bool TokensExactAmounts(bool goDeeper, struct CCcontract_info *cpTokens, int64_t &inputs, int64_t &outputs, Eval* eval, const CTransaction &tx, uint256 tokenid);
//int64_t IsTokensvout(bool goDeeper, bool checkPubkeys, struct CCcontract_info *cp, Eval* eval, std::vector<uint8_t> &origpubkey, const CTransaction& tx, int32_t v, uint256 reftokenid, std::vector<CPubKey> vinPubkeys);
std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description);
std::string CreateToken(int64_t txfee, int64_t assetsupply, std::string name, std::string description, std::vector<uint8_t> nonfungibleData);
std::string TokenTransfer(int64_t txfee, uint256 assetid, std::vector<uint8_t> destpubkey, int64_t total);
bool ExtractTokensVinPubkeys(CTransaction tx, std::vector<CPubKey> &vinPubkeys);
int64_t HasBurnedTokensvouts(struct CCcontract_info *cp, Eval* eval, const CTransaction& tx, uint256 reftokenid);
int64_t GetTokenBalance(CPubKey pk, uint256 tokenid);
UniValue TokenInfo(uint256 tokenid);
UniValue TokenList();
//this is in CCinclude.h int64_t AddTokenCCInputs(struct CCcontract_info *cp, CMutableTransaction &mtx, CPubKey pk, uint256 tokenid, int64_t total, int32_t maxinputs);
//this is in CCinclude.h uint8_t DecodeTokenCreateOpRet(const CScript &scriptPubKey,std::vector<uint8_t> &origpubkey,std::string &name,std::string &description);
#endif

View File

@@ -46,9 +46,9 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
CTransaction vintx; std::string hex; CPubKey globalpk; uint256 hashBlock; uint64_t mask=0,nmask=0,vinimask=0;
int64_t utxovalues[CC_MAXVINS],change,normalinputs=0,totaloutputs=0,normaloutputs=0,totalinputs=0,normalvins=0,ccvins=0;
int32_t i,flag,utxovout,n,err = 0;
char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], tokensunspendable[64];
uint8_t *privkey, myprivkey[32], unspendablepriv[32], tokensunspendablepriv[32], *msg32 = 0;
CC *mycond=0, *othercond=0, *othercond2=0,*othercond4=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL;
char myaddr[64], destaddr[64], unspendable[64], mytokensaddr[64], mysingletokensaddr[64], unspendabletokensaddr[64],CC1of2CCaddr[64];
uint8_t *privkey, myprivkey[32], unspendablepriv[32], /*tokensunspendablepriv[32],*/ *msg32 = 0;
CC *mycond=0, *othercond=0, *othercond2=0,*othercond4=0, *othercond3=0, *othercond1of2=NULL, *othercond1of2tokens = NULL, *cond, *condCC2=0,*mytokenscond = NULL, *mysingletokenscond = NULL, *othertokenscond = NULL;
CPubKey unspendablepk /*, tokensunspendablepk*/;
struct CCcontract_info *cpTokens, tokensC;
globalpk = GetUnspendable(cp,0);
@@ -69,26 +69,28 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
GetCCaddress(cp,myaddr,mypk);
mycond = MakeCCcond1(cp->evalcode,mypk);
// to spend from single-eval evalcode 'unspendable'
// to spend from single-eval evalcode 'unspendable' cc addr
unspendablepk = GetUnspendable(cp, unspendablepriv);
GetCCaddress(cp, unspendable, unspendablepk);
othercond = MakeCCcond1(cp->evalcode, unspendablepk);
GetCCaddress1of2(cp,CC1of2CCaddr,unspendablepk,unspendablepk);
//printf("evalcode.%d (%s)\n",cp->evalcode,unspendable);
// tokens support:
// to spend from dual-eval mypk vout
// to spend from dual/three-eval mypk vout
GetTokensCCaddress(cp, mytokensaddr, mypk);
mytokenscond = MakeTokensCCcond1(cp->evalcode, mypk);
// NOTE: if additionalEvalcode2 is not set it is a dual-eval (not three-eval) cc cond:
mytokenscond = MakeTokensCCcond1(cp->evalcode, cp->additionalTokensEvalcode2, mypk);
// to spend from single-eval EVAL_TOKENS mypk
cpTokens = CCinit(&tokensC, EVAL_TOKENS);
GetCCaddress(cpTokens, mysingletokensaddr, mypk);
mysingletokenscond = MakeCCcond1(EVAL_TOKENS, mypk);
// to spend from dual-eval EVAL_TOKEN+evalcode 'unspendable' pk
//tokensunspendablepk = GetUnspendable(cpTokens, tokensunspendablepriv);
GetTokensCCaddress(cp, tokensunspendable, unspendablepk);
othertokenscond = MakeTokensCCcond1(cp->evalcode, unspendablepk);
// to spend from dual/three-eval EVAL_TOKEN+evalcode 'unspendable' pk:
GetTokensCCaddress(cp, unspendabletokensaddr, unspendablepk); // it may be a three-eval cc, if cp->additionalEvalcode2 is set
othertokenscond = MakeTokensCCcond1(cp->evalcode, cp->additionalTokensEvalcode2, unspendablepk);
//Reorder vins so that for multiple normal vins all other except vin0 goes to the end
//This is a must to avoid hardfork change of validation in every CC, because there could be maximum one normal vin at the begining with current validation.
@@ -154,10 +156,11 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
else
{
Getscriptaddress(destaddr,vintx.vout[utxovout].scriptPubKey);
//fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s)\n",i,(double)utxovalues[i]/COIN,destaddr);
//std::cerr << "FinalizeCCtx() searching destaddr=" << destaddr << " myaddr=" << myaddr << std::endl;
if( strcmp(destaddr,myaddr) == 0 )
//fprintf(stderr,"FinalizeCCTx() vin.%d is CC %.8f -> (%s) vs %s\n",i,(double)utxovalues[i]/COIN,destaddr,cp->unspendableaddr2);
//std::cerr << "FinalizeCCtx() searching destaddr=" << destaddr << " for vin[" << i << "] satoshis=" << utxovalues[i] << std::endl;
if( strcmp(destaddr, myaddr) == 0 )
{
//fprintf(stderr, "FinalizeCCTx() matched cc myaddr (%s)\n", myaddr);
privkey = myprivkey;
cond = mycond;
}
@@ -165,33 +168,33 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
{
privkey = myprivkey;
cond = mytokenscond;
//fprintf(stderr,"FinalizeCCTx() matched dual-eval TokensCC1vout CC addr.(%s)\n",mytokensaddr);
//fprintf(stderr,"FinalizeCCTx() matched dual-eval TokensCC1vout my token addr.(%s)\n",mytokensaddr);
}
else if (strcmp(destaddr, mysingletokensaddr) == 0) // if this is TokensCC1vout
{
privkey = myprivkey;
cond = mysingletokenscond;
//fprintf(stderr, "FinalizeCCTx() matched single-eval token CC1vout CC addr.(%s)\n", mytokensaddr);
//fprintf(stderr, "FinalizeCCTx() matched single-eval token CC1vout my token addr.(%s)\n", mytokensaddr);
}
else if ( strcmp(destaddr,unspendable) == 0 )
{
privkey = unspendablepriv;
cond = othercond;
//fprintf(stderr,"FinalizeCCTx() matched unspendable CC addr.(%s)\n",unspendable);
//fprintf(stderr,"FinalizeCCTx evalcode(%d) matched unspendable CC addr.(%s)\n",cp->evalcode,unspendable);
}
else if (strcmp(destaddr, tokensunspendable) == 0)
else if (strcmp(destaddr, unspendabletokensaddr) == 0)
{
privkey = unspendablepriv;
cond = othertokenscond;
//fprintf(stderr,"FinalizeCCTx() matched tokensunspendable CC addr.(%s)\n",unspendable);
//fprintf(stderr,"FinalizeCCTx() matched unspendabletokensaddr dual/three-eval CC addr.(%s)\n",unspendabletokensaddr);
}
// check if this is the 2nd additional evalcode + 'unspendable' cc addr:
else if ( strcmp(destaddr,cp->unspendableaddr2) == 0)
else if ( strcmp(destaddr, cp->unspendableaddr2) == 0)
{
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable2!\n",cp->unspendableaddr2);
privkey = cp->unspendablepriv2;
if ( othercond2 == 0 )
othercond2 = MakeCCcond1(cp->evalcode2, cp->unspendablepk2);
if( othercond2 == 0 )
othercond2 = MakeCCcond1(cp->unspendableEvalcode2, cp->unspendablepk2);
cond = othercond2;
}
// check if this is 3rd additional evalcode + 'unspendable' cc addr:
@@ -199,26 +202,36 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
{
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable3!\n",cp->unspendableaddr3);
privkey = cp->unspendablepriv3;
if ( othercond3 == 0 )
othercond3 = MakeCCcond1(cp->evalcode3,cp->unspendablepk3);
if( othercond3 == 0 )
othercond3 = MakeCCcond1(cp->unspendableEvalcode3, cp->unspendablepk3);
cond = othercond3;
}
// check if this is spending from 1of2 cc coins addr:
else if (strcmp(cp->coins1of2addr, destaddr) == 0)
{
//fprintf(stderr,"FinalizeCCTx() matched %s unspendable1of2!\n",cp->coins1of2addr);
privkey = myprivkey;
privkey = cp->coins1of2priv;//myprivkey;
if (othercond1of2 == 0)
othercond1of2 = MakeCCcond1of2(cp->evalcode, cp->coins1of2pk[0], cp->coins1of2pk[1]);
cond = othercond1of2;
}
else if ( strcmp(CC1of2CCaddr,destaddr) == 0 )
{
//fprintf(stderr,"FinalizeCCTx() matched %s CC1of2CCaddr!\n",CC1of2CCaddr);
privkey = unspendablepriv;
if (condCC2 == 0)
condCC2 = MakeCCcond1of2(cp->evalcode,unspendablepk,unspendablepk);
cond = condCC2;
}
// check if this is spending from 1of2 cc tokens addr:
else if (strcmp(cp->tokens1of2addr, destaddr) == 0)
{
//fprintf(stderr,"FinalizeCCTx() matched %s cp->tokens1of2addr!\n", cp->tokens1of2addr);
privkey = myprivkey;
if (othercond1of2tokens == 0)
othercond1of2tokens = MakeTokensCCcond1of2(cp->evalcode, cp->tokens1of2pk[0], cp->tokens1of2pk[1]);
// NOTE: if additionalEvalcode2 is not set then it is dual-eval cc else three-eval cc
// TODO: verify evalcodes order if additionalEvalcode2 is not 0
othercond1of2tokens = MakeTokensCCcond1of2(cp->evalcode, cp->additionalTokensEvalcode2, cp->tokens1of2pk[0], cp->tokens1of2pk[1]);
cond = othercond1of2tokens;
}
else
@@ -242,7 +255,7 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
if ( flag == 0 )
{
fprintf(stderr,"CC signing error: vini.%d has unknown CC address.(%s)\n",i,destaddr);
continue;
return("");
}
}
uint256 sighash = SignatureHash(CCPubKey(cond), mtx, i, SIGHASH_ALL, utxovalues[i],consensusBranchId, &txdata);
@@ -267,6 +280,8 @@ std::string FinalizeCCTx(uint64_t CCmask,struct CCcontract_info *cp,CMutableTran
}
if ( mycond != 0 )
cc_free(mycond);
if ( condCC2 != 0 )
cc_free(condCC2);
if ( othercond != 0 )
cc_free(othercond);
if ( othercond2 != 0 )
@@ -341,7 +356,7 @@ int32_t CCgettxout(uint256 txid,int32_t vout,int32_t mempoolflag)
CCoinsViewMemPool view(pcoinsTip, mempool);
if (!view.GetCoins(txid, coins))
return(-1);
if ( myIsutxo_spentinmempool(txid,vout) != 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) != 0 )
return(-1);
}
else
@@ -380,7 +395,7 @@ int64_t CCaddress_balance(char *coinaddr)
int64_t CCfullsupply(uint256 tokenid)
{
uint256 hashBlock; int32_t numvouts; CTransaction tx; std::vector<uint8_t> origpubkey; std::string name,description;
if ( GetTransaction(tokenid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
if ( myGetTransaction(tokenid,tx,hashBlock) != 0 && (numvouts= tx.vout.size()) > 0 )
{
if (DecodeTokenCreateOpRet(tx.vout[numvouts-1].scriptPubKey,origpubkey,name,description))
{
@@ -390,9 +405,9 @@ int64_t CCfullsupply(uint256 tokenid)
return(0);
}
int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
int64_t CCtoken_balance(char *coinaddr,uint256 reftokenid)
{
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 assetid,assetid2,txid,hashBlock;
int64_t price,sum = 0; int32_t numvouts; CTransaction tx; uint256 tokenid,txid,hashBlock;
std::vector<uint8_t> vopretExtra;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
uint8_t evalCode;
@@ -401,11 +416,11 @@ int64_t CCtoken_balance(char *coinaddr,uint256 tokenid)
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 )
if ( myGetTransaction(txid,tx,hashBlock) != 0 && (numvouts=tx.vout.size()) > 0 )
{
char str[65]; fprintf(stderr,"check %s %.8f\n",uint256_str(str,txid),(double)it->second.satoshis/COIN);
char str[65];
std::vector<CPubKey> voutTokenPubkeys;
if ( DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, assetid, voutTokenPubkeys, vopretExtra) != 0 && assetid == tokenid )
if ( reftokenid==txid || (DecodeTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCode, tokenid, voutTokenPubkeys, vopretExtra) != 0 && reftokenid == tokenid))
{
sum += it->second.satoshis;
}
@@ -471,7 +486,7 @@ int32_t CC_vinselect(int32_t *aboveip,int64_t *abovep,int32_t *belowip,int64_t *
int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int32_t maxinputs)
{
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=64; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector<COutput> vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up;
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=CC_MAXVINS; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; uint256 txid,hashBlock; std::vector<COutput> vecOutputs; CTransaction tx; struct CC_utxo *utxos,*up;
#ifdef ENABLE_WALLET
assert(pwalletMain != NULL);
const CKeyStore& keystore = *pwalletMain;
@@ -507,7 +522,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
if ( i != n )
continue;
}
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
up = &utxos[n++];
up->txid = txid;
@@ -564,7 +579,7 @@ int64_t AddNormalinputs(CMutableTransaction &mtx,CPubKey mypk,int64_t total,int3
int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinputs)
{
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=64; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; char coinaddr[64]; uint256 txid,hashBlock; CTransaction tx; struct CC_utxo *utxos,*up;
int32_t abovei,belowi,ind,vout,i,n = 0,maxutxos=CC_MAXVINS; int64_t sum,threshold,above,below; int64_t remains,nValue,totalinputs = 0; char coinaddr[64]; uint256 txid,hashBlock; CTransaction tx; struct CC_utxo *utxos,*up;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
utxos = (struct CC_utxo *)calloc(maxutxos,sizeof(*utxos));
threshold = total/(maxinputs+1);
@@ -598,7 +613,7 @@ int64_t AddNormalinputs2(CMutableTransaction &mtx,int64_t total,int32_t maxinput
if ( i != n )
continue;
}
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
up = &utxos[n++];
up->txid = txid;

View File

@@ -76,7 +76,8 @@ CTxOut MakeCC1of2vout(uint8_t evalcode,CAmount nValue,CPubKey pk1,CPubKey pk2)
return(vout);
}
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2)
// make three-eval (token+evalcode+evalcode2) 1of2 cryptocondition:
CC *MakeTokensCCcond1of2(uint8_t evalcode, uint8_t evalcode2, CPubKey pk1, CPubKey pk2)
{
// make 1of2 sigs cond
std::vector<CC*> pks;
@@ -85,44 +86,68 @@ CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2)
std::vector<CC*> thresholds;
thresholds.push_back( CCNewEval(E_MARSHAL(ss << evalcode)) );
if( evalcode != EVAL_TOKENS ) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1of2()!
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc
if( evalcode != EVAL_TOKENS ) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1of2()!
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
if( evalcode2 != 0 )
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode
thresholds.push_back(CCNewThreshold(1, pks)); // this is 1 of 2 sigs cc
return CCNewThreshold(thresholds.size(), thresholds);
}
// overload to make two-eval (token+evalcode) 1of2 cryptocondition:
CC *MakeTokensCCcond1of2(uint8_t evalcode, CPubKey pk1, CPubKey pk2) {
return MakeTokensCCcond1of2(evalcode, 0, pk1, pk2);
}
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk)
// make three-eval (token+evalcode+evalcode2) cryptocondition:
CC *MakeTokensCCcond1(uint8_t evalcode, uint8_t evalcode2, CPubKey pk)
{
std::vector<CC*> pks;
pks.push_back(CCNewSecp256k1(pk));
std::vector<CC*> thresholds;
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode)));
if (evalcode != EVAL_TOKENS) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1()!
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
thresholds.push_back(CCNewThreshold(1, pks)); // signature
if (evalcode != EVAL_TOKENS) // if evalCode == EVAL_TOKENS, it is actually MakeCCcond1()!
thresholds.push_back(CCNewEval(E_MARSHAL(ss << (uint8_t)EVAL_TOKENS))); // this is eval token cc
if (evalcode2 != 0)
thresholds.push_back(CCNewEval(E_MARSHAL(ss << evalcode2))); // add optional additional evalcode
thresholds.push_back(CCNewThreshold(1, pks)); // signature
return CCNewThreshold(thresholds.size(), thresholds);
}
// overload to make two-eval (token+evalcode) cryptocondition:
CC *MakeTokensCCcond1(uint8_t evalcode, CPubKey pk) {
return MakeTokensCCcond1(evalcode, 0, pk);
}
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2)
// make three-eval (token+evalcode+evalcode2) 1of2 cc vout:
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk1, CPubKey pk2)
{
CTxOut vout;
CC *payoutCond = MakeTokensCCcond1of2(evalcode, pk1, pk2);
CC *payoutCond = MakeTokensCCcond1of2(evalcode, evalcode2, pk1, pk2);
vout = CTxOut(nValue, CCPubKey(payoutCond));
cc_free(payoutCond);
return(vout);
}
// overload to make two-eval (token+evalcode) 1of2 cc vout:
CTxOut MakeTokensCC1of2vout(uint8_t evalcode, CAmount nValue, CPubKey pk1, CPubKey pk2) {
return MakeTokensCC1of2vout(evalcode, 0, nValue, pk1, pk2);
}
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk)
// make three-eval (token+evalcode+evalcode2) cc vout:
CTxOut MakeTokensCC1vout(uint8_t evalcode, uint8_t evalcode2, CAmount nValue, CPubKey pk)
{
CTxOut vout;
CC *payoutCond = MakeTokensCCcond1(evalcode, pk);
CC *payoutCond = MakeTokensCCcond1(evalcode, evalcode2, pk);
vout = CTxOut(nValue, CCPubKey(payoutCond));
cc_free(payoutCond);
return(vout);
}
// overload to make two-eval (token+evalcode) cc vout:
CTxOut MakeTokensCC1vout(uint8_t evalcode, CAmount nValue, CPubKey pk) {
return MakeTokensCC1vout(evalcode, 0, nValue, pk);
}
CC* GetCryptoCondition(CScript const& scriptSig)
{
@@ -227,36 +252,40 @@ CPubKey pubkey2pk(std::vector<uint8_t> pubkey)
return(pk);
}
// set additional 'unspendable' addr
void CCaddr2set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
{
cp->evalcode2 = evalcode;
cp->unspendableEvalcode2 = evalcode;
cp->unspendablepk2 = pk;
memcpy(cp->unspendablepriv2,priv,32);
strcpy(cp->unspendableaddr2,coinaddr);
}
// set yet another additional 'unspendable' addr
void CCaddr3set(struct CCcontract_info *cp,uint8_t evalcode,CPubKey pk,uint8_t *priv,char *coinaddr)
{
cp->evalcode3 = evalcode;
cp->unspendableEvalcode3 = evalcode;
cp->unspendablepk3 = pk;
memcpy(cp->unspendablepriv3,priv,32);
strcpy(cp->unspendableaddr3,coinaddr);
}
// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 cryptocondition vout:
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr)
void CCaddr1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2,uint8_t *priv,char *coinaddr)
{
cp->coins1of2pk[0] = pk1;
cp->coins1of2pk[1] = pk2;
strcpy(cp->coins1of2addr, coinaddr);
memcpy(cp->coins1of2priv,priv,32);
strcpy(cp->coins1of2addr,coinaddr);
}
// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 tokens cryptocondition vout:
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *coinaddr)
// set pubkeys, myprivkey and 1of2 cc addr for spending from 1of2 token cryptocondition vout
// to get tokenaddr use GetTokensCCaddress()
void CCaddrTokens1of2set(struct CCcontract_info *cp, CPubKey pk1, CPubKey pk2, char *tokenaddr)
{
cp->tokens1of2pk[0] = pk1;
cp->tokens1of2pk[1] = pk2;
strcpy(cp->tokens1of2addr, coinaddr);
strcpy(cp->tokens1of2addr, tokenaddr);
}
bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
@@ -271,6 +300,18 @@ bool Getscriptaddress(char *destaddr,const CScript &scriptPubKey)
return(false);
}
bool GetCustomscriptaddress(char *destaddr,const CScript &scriptPubKey,uint8_t taddr,uint8_t prefix, uint8_t prefix2)
{
CTxDestination address; txnouttype whichType;
if ( ExtractDestination(scriptPubKey,address) != 0 )
{
strcpy(destaddr,(char *)CCustomBitcoinAddress(address,taddr,prefix,prefix2).ToString().c_str());
return(true);
}
//fprintf(stderr,"ExtractDestination failed\n");
return(false);
}
bool GetCCParams(Eval* eval, const CTransaction &tx, uint32_t nIn,
CTransaction &txOut, std::vector<std::vector<unsigned char>> &preConditions, std::vector<std::vector<unsigned char>> &params)
{
@@ -331,6 +372,16 @@ CPubKey CCtxidaddr(char *txidaddr,uint256 txid)
return(pk);
}
CPubKey CCCustomtxidaddr(char *txidaddr,uint256 txid,uint8_t taddr,uint8_t prefix,uint8_t prefix2)
{
uint8_t buf33[33]; CPubKey pk;
buf33[0] = 0x02;
endiancpy(&buf33[1],(uint8_t *)&txid,32);
pk = buf2pk(buf33);
GetCustomscriptaddress(txidaddr,CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG,taddr,prefix,prefix2);
return(pk);
}
bool _GetCCaddress(char *destaddr,uint8_t evalcode,CPubKey pk)
{
CC *payoutCond;
@@ -351,11 +402,11 @@ bool GetCCaddress(struct CCcontract_info *cp,char *destaddr,CPubKey pk)
return(_GetCCaddress(destaddr,cp->evalcode,pk));
}
bool _GetTokensCCaddress(char *destaddr, uint8_t evalcode, CPubKey pk)
bool _GetTokensCCaddress(char *destaddr, uint8_t evalcode, uint8_t evalcode2, CPubKey pk)
{
CC *payoutCond;
destaddr[0] = 0;
if ((payoutCond = MakeTokensCCcond1(evalcode, pk)) != 0)
if ((payoutCond = MakeTokensCCcond1(evalcode, evalcode2, pk)) != 0)
{
Getscriptaddress(destaddr, CCPubKey(payoutCond));
cc_free(payoutCond);
@@ -363,12 +414,13 @@ bool _GetTokensCCaddress(char *destaddr, uint8_t evalcode, CPubKey pk)
return(destaddr[0] != 0);
}
// get scriptPubKey adddress for three/dual eval token cc vout
bool GetTokensCCaddress(struct CCcontract_info *cp, char *destaddr, CPubKey pk)
{
destaddr[0] = 0;
if (pk.size() == 0)
pk = GetUnspendable(cp, 0);
return(_GetTokensCCaddress(destaddr, cp->evalcode, pk));
return(_GetTokensCCaddress(destaddr, cp->evalcode, cp->additionalTokensEvalcode2, pk));
}
@@ -384,11 +436,12 @@ bool GetCCaddress1of2(struct CCcontract_info *cp,char *destaddr,CPubKey pk,CPubK
return(destaddr[0] != 0);
}
// get scriptPubKey adddress for three/dual eval token 1of2 cc vout
bool GetTokensCCaddress1of2(struct CCcontract_info *cp, char *destaddr, CPubKey pk, CPubKey pk2)
{
CC *payoutCond;
destaddr[0] = 0;
if ((payoutCond = MakeTokensCCcond1of2(cp->evalcode, pk, pk2)) != 0)
if ((payoutCond = MakeTokensCCcond1of2(cp->evalcode, cp->additionalTokensEvalcode2, pk, pk2)) != 0) // if additionalTokensEvalcode2 not set then it is dual-eval cc else three-eval cc
{
Getscriptaddress(destaddr, CCPubKey(payoutCond));
cc_free(payoutCond);
@@ -442,6 +495,20 @@ bool PreventCC(Eval* eval,const CTransaction &tx,int32_t preventCCvins,int32_t n
return(true);
}
bool priv2addr(char *coinaddr,uint8_t *buf33,uint8_t priv32[32])
{
CKey priv; CPubKey pk; int32_t i; uint8_t *src;
priv.SetKey32(priv32);
pk = priv.GetPubKey();
if ( buf33 != 0 )
{
src = (uint8_t *)pk.begin();
for (i=0; i<33; i++)
buf33[i] = src[i];
}
return(Getscriptaddress(coinaddr, CScript() << ParseHex(HexStr(pk)) << OP_CHECKSIG));
}
std::vector<uint8_t> Mypubkey()
{
extern uint8_t NOTARY_PUBKEY33[33];
@@ -456,7 +523,7 @@ std::vector<uint8_t> Mypubkey()
bool Myprivkey(uint8_t myprivkey[])
{
char coinaddr[64]; std::string strAddress; char *dest; int32_t i,n; CBitcoinAddress address; CKeyID keyID; CKey vchSecret;
char coinaddr[64],checkaddr[64]; std::string strAddress; char *dest; int32_t i,n; CBitcoinAddress address; CKeyID keyID; CKey vchSecret; uint8_t buf33[33];
if ( Getscriptaddress(coinaddr,CScript() << Mypubkey() << OP_CHECKSIG) != 0 )
{
n = (int32_t)strlen(coinaddr);
@@ -477,7 +544,13 @@ bool Myprivkey(uint8_t myprivkey[])
fprintf(stderr,"0x%02x, ",myprivkey[i]);
fprintf(stderr," found privkey for %s!\n",dest);
}
return(true);
if ( priv2addr(checkaddr,buf33,myprivkey) != 0 )
{
if ( buf2pk(buf33) == Mypubkey() && strcmp(checkaddr,coinaddr) == 0 )
return(true);
else printf("mismatched privkey -> addr %s vs %s\n",checkaddr,coinaddr);
}
return(false);
}
#endif
}
@@ -495,7 +568,7 @@ CPubKey GetUnspendable(struct CCcontract_info *cp,uint8_t *unspendablepriv)
void CCclearvars(struct CCcontract_info *cp)
{
cp->evalcode2 = cp->evalcode3 = 0;
cp->unspendableEvalcode2 = cp->unspendableEvalcode3 = 0;
cp->unspendableaddr2[0] = cp->unspendableaddr3[0] = 0;
}
@@ -614,6 +687,9 @@ bool ProcessCC(struct CCcontract_info *cp,Eval* eval, std::vector<uint8_t> param
from_mempool = 1;
height &= ((1<<30) - 1);
}
if (cp->validate == NULL)
return eval->Invalid("validation not supported for eval code");
//fprintf(stderr,"KOMODO_CONNECTING.%d mempool.%d vs CCactive.%d\n",height,from_mempool,KOMODO_CCACTIVATE);
// there is a chance CC tx is valid in mempool, but invalid when in block, so we cant filter duplicate requests. if any of the vins are spent, for example
//txid = ctx.GetHash();
@@ -675,4 +751,4 @@ bool CClib_Dispatch(const CC *cond,Eval *eval,std::vector<uint8_t> paramsNull,co
return(false); //eval->Invalid("error in CClib_validate");
}
return eval->Invalid("cclib CC must have evalcode between 16 and 127");
}
}

View File

@@ -3,7 +3,7 @@ CC = gcc
CC_DARWIN = g++-6
CC_WIN = x86_64-w64-mingw32-gcc-posix
CFLAGS_DARWIN = -std=c++11 -arch x86_64 -I/usr/local/Cellar/gcc\@6/6.4.0_2/include/c++/6.4.0/ -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -c -Wl,-undefined -Wl,dynamic_lookup -dynamiclib
CFLAGS = -std=c++11 -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I../../depends/x86_64-unknown-linux-gnu/include -I.. -I. -fPIC -shared -c
CFLAGS = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c
CFLAGS_WIN = -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c
DEBUGFLAGS = -O0 -D _DEBUG
RELEASEFLAGS = -O2 -D NDEBUG -combine -fwhole-program
@@ -13,7 +13,7 @@ $(info $(OS))
TARGET = ../libcc.so
TARGET_DARWIN = ../libcc.dylib
TARGET_WIN = ../libcc.dll
SOURCES = cclib.cpp
SOURCES = cclib.cpp
#HEADERS = $(shell echo ../cryptoconditions/include/*.h)
all: $(TARGET)

View File

@@ -14,6 +14,7 @@
******************************************************************************/
#include "CCassets.h"
#include "CCtokens.h"
/*
Assets can be created or transferred.
@@ -129,33 +130,45 @@
bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
static uint256 zero;
CTxDestination address; CTransaction vinTx,createTx; uint256 hashBlock,assetid,assetid2;
int32_t i,starti,numvins,numvouts,preventCCvins,preventCCvouts;
int64_t remaining_price,nValue,assetoshis,outputs,inputs,tmpprice,totalunits,ignore; std::vector<uint8_t> origpubkey,tmporigpubkey,ignorepubkey;
CTxDestination address;
CTransaction vinTx, createTx;
uint256 hashBlock, assetid, assetid2;
int32_t i,starti, numvins, numvouts, preventCCvins, preventCCvouts;
int64_t remaining_price, nValue, assetoshis, outputsDummy,inputs,tmpprice,totalunits,ignore;
std::vector<uint8_t> origpubkey, tmporigpubkey, ignorepubkey, vopretNonfungible, vopretNonfungibleDummy;
uint8_t funcid, evalCodeInOpret;
char destaddr[64], origaddr[64], assetsCCaddr[64], userTokensCCaddr[64]; //, signleEvalTokensCCaddr[64];
char destaddr[64], origNormalAddr[64], origTokensCCaddr[64], origCCaddrDummy[64];
char tokensDualEvalUnspendableCCaddr[64], origAssetsCCaddr[64];
//return true;
//CPubKey unspendableTokensPk = GetUnspendable(cpTokens, NULL);
//CPubKey unspendableAssetsPk = GetUnspendable(cpAssets, NULL);
//GetCCaddress(cpTokens, tokensUnspendableCCaddr, unspendableTokensPk);
numvins = tx.vin.size();
numvouts = tx.vout.size();
outputs = inputs = 0;
outputsDummy = inputs = 0;
preventCCvins = preventCCvouts = -1;
// add specific chains exceptions for old token support:
if (strcmp(ASSETCHAINS_SYMBOL, "SEC") == 0 && chainActive.Height() <= 144073)
return true;
if (strcmp(ASSETCHAINS_SYMBOL, "MGNX") == 0 && chainActive.Height() <= 210190)
return true;
if (numvouts == 0)
return eval->Invalid("AssetValidate: no vouts");
if((funcid = DecodeAssetTokenOpRet(tx.vout[numvouts-1].scriptPubKey, evalCodeInOpret, assetid, assetid2, remaining_price, origpubkey)) == 0 )
return eval->Invalid("AssetValidate: invalid opreturn payload");
// non-fungible tokens support:
GetNonfungibleData(assetid, vopretNonfungible);
if (vopretNonfungible.size() > 0)
cpAssets->additionalTokensEvalcode2 = vopretNonfungible.begin()[0];
// find dual-eval tokens unspendable addr:
char tokensUnspendableAddr[64],origpubkeyCCaddr[64];
GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
GetCCaddress(cpAssets, origpubkeyCCaddr, origpubkey);
GetTokensCCaddress(cpAssets, tokensDualEvalUnspendableCCaddr, GetUnspendable(cpAssets, NULL));
// this is for marker validation:
GetCCaddress(cpAssets, origAssetsCCaddr, origpubkey);
// we need this for validating single-eval tokens' vins/vous:
struct CCcontract_info *cpTokens, tokensC;
@@ -170,7 +183,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("cant find asset create txid");
else if( funcid != 'o' && funcid != 'x' && assetid2 != zero && eval->GetTxUnconfirmed(assetid2, createTx, hashBlock) == 0 )
return eval->Invalid("cant find asset2 create txid");
else if( IsCCInput(tx.vin[0].scriptSig) != 0 )
else if( IsCCInput(tx.vin[0].scriptSig) != 0 ) // vin0 should be normal vin
return eval->Invalid("illegal asset vin0");
else if( numvouts < 2 )
return eval->Invalid("too few vouts"); // it was if(numvouts < 1) but it refers at least to vout[1] below
@@ -184,7 +197,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
if( assetid == zero )
return eval->Invalid("illegal assetid");
else if (!AssetCalcAmounts(cpAssets, inputs, outputs, eval, tx, assetid)) { // Only set inputs and outputs. NOTE: we do not need to check cc inputs == cc outputs
else if (!AssetCalcAmounts(cpAssets, inputs, outputsDummy/*outputsDummy is calculated incorrectly but not used*/, eval, tx, assetid)) { // Only set inputs and outputs. NOTE: we do not need to check cc inputs == cc outputs
return false; // returns false if some problems with reading vintxes
}
}
@@ -219,9 +232,13 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.1: CC output for marker
//vout.2: normal output for change (if any)
// vout.n-1: opreturn [EVAL_ASSETS] ['b'] [assetid] [amount of asset required] [origpubkey]
// as we don't use tokenconvert we should not be here:
return eval->Invalid("invalid asset funcid (b)");
if( remaining_price == 0 )
return eval->Invalid("illegal null amount for buyoffer");
else if( ConstrainVout(tx.vout[0],1,cpAssets->unspendableCCaddr,0) == 0 )
else if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr,0) == 0 ) // coins to assets unspendable cc addr
return eval->Invalid("invalid vout for buyoffer");
preventCCvins = 1;
preventCCvouts = 1;
@@ -236,13 +253,13 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.1: vin.2 back to users pubkey
//vout.2: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['o']
if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 )
if( (nValue= AssetValidateBuyvin(cpAssets, eval, tmpprice, tmporigpubkey, origCCaddrDummy, origNormalAddr, tx, assetid)) == 0 )
return(false);
else if( ConstrainVout(tx.vout[0],0, origaddr, nValue) == 0 )
else if( ConstrainVout(tx.vout[0],0, origNormalAddr, nValue) == 0 )
return eval->Invalid("invalid refund for cancelbuy");
preventCCvins = 3;
preventCCvouts = 0;
fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origaddr);
fprintf(stderr,"cancelbuy validated to origaddr.(%s)\n",origNormalAddr);
break;
case 'B': // fillbuy:
@@ -257,7 +274,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.n-1: opreturn [EVAL_ASSETS] ['B'] [assetid] [remaining asset required] [origpubkey]
preventCCvouts = 4;
if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, assetsCCaddr, origaddr, tx, assetid)) == 0 )
if( (nValue = AssetValidateBuyvin(cpAssets, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 )
return(false);
else if( numvouts < 4 )
return eval->Invalid("not enough vouts for fillbuy");
@@ -267,24 +284,24 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
{
if( nValue != tx.vout[0].nValue + tx.vout[1].nValue )
return eval->Invalid("locked value doesnt match vout0+1 fillbuy");
else if( tx.vout[4].scriptPubKey.IsPayToCryptoCondition() != 0 )
else if( tx.vout[4].scriptPubKey.IsPayToCryptoCondition() != 0 ) // if cc change present
{
if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, 0) == 0 ) // tokens on user cc addr
if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, 0) == 0 ) // tokens to originator cc addr (tokens+nonfungible evals)
return eval->Invalid("vout2 doesnt go to origpubkey fillbuy");
else if ( inputs != tx.vout[2].nValue + tx.vout[4].nValue )
return eval->Invalid("asset inputs doesnt match vout2+3 fillbuy");
}
else if( ConstrainVout(tx.vout[2], 1, assetsCCaddr, inputs) == 0 ) // tokens on user cc addr
else if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, inputs) == 0 ) // tokens to originator cc addr (tokens+nonfungible evals)
return eval->Invalid("vout2 doesnt match inputs fillbuy");
else if( ConstrainVout(tx.vout[1],0,0,0) == 0 )
else if( ConstrainVout(tx.vout[1], 0, NULL, 0) == 0 )
return eval->Invalid("vout1 is CC for fillbuy");
else if( ConstrainVout(tx.vout[3], 1, origpubkeyCCaddr, 10000) == 0 )
else if( ConstrainVout(tx.vout[3], 1, origAssetsCCaddr, 10000) == 0 ) // marker to asset cc addr
return eval->Invalid("invalid marker for original pubkey");
else if( ValidateBidRemainder(remaining_price, tx.vout[0].nValue, nValue, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false )
return eval->Invalid("mismatched remainder for fillbuy");
else if( remaining_price != 0 )
{
if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr, 0) == 0 ) // coins on asset unspendable cc addr
if( ConstrainVout(tx.vout[0], 1, cpAssets->unspendableCCaddr, 0) == 0 ) // coins to asset unspendable cc addr
return eval->Invalid("mismatched vout0 AssetsCCaddr for fillbuy");
}
}
@@ -301,25 +318,30 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.3: normal output for change (if any)
//'s'.vout.n-1: opreturn [EVAL_ASSETS] ['s'] [assetid] [amount of native coin required] [origpubkey]
//'e'.vout.n-1: opreturn [EVAL_ASSETS] ['e'] [assetid] [assetid2] [amount of asset2 required] [origpubkey]
// as we don't use tokenconvert we should not be here:
return eval->Invalid("invalid asset funcid (s)");
preventCCvouts = 2;
if( remaining_price == 0 )
return eval->Invalid("illegal null remaining_price for selloffer");
if ( tx.vout[1].scriptPubKey.IsPayToCryptoCondition() == 0 )
return eval->Invalid("invalid normal vout1 for sellvin");
if( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) // cc change
if( tx.vout[2].scriptPubKey.IsPayToCryptoCondition() != 0 ) // if cc change presents
{
preventCCvouts++;
if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // check also cc vout[0]
if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, 0) == 0 ) // tokens to tokens unspendable cc addr. TODO: this in incorrect, should be assets if we got here!
return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer");
else if( tx.vout[0].nValue + tx.vout[2].nValue != inputs )
return eval->Invalid("mismatched vout0+vout2 total for selloffer");
}
else if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, inputs) == 0 ) // no cc change, just vout[0]
// no cc change:
else if( ConstrainVout(tx.vout[0], 1, (char *)cpTokens->unspendableCCaddr, inputs) == 0 ) // tokens to tokens unspendable cc addr TODO: this in incorrect, should be assets if got here!
return eval->Invalid("mismatched vout0 TokensCCaddr for selloffer");
//fprintf(stderr,"remaining.%d for sell\n",(int32_t)remaining_price);
break;
case 'x': // cancel
case 'x': // cancel sell
//vin.0: normal input
//vin.1: unspendable.(vout.0 from exchange or selloffer) sellTx/exchangeTx.vout[0] inputTx
//vin.2: CC marker from selloffer for txfee
@@ -328,9 +350,9 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.2: normal output for change (if any)
//vout.n-1: opreturn [EVAL_ASSETS] ['x'] [assetid]
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 ) // NOTE:
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, tmpprice, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 ) // NOTE:
return(false);
else if( ConstrainVout(tx.vout[0], 1, userTokensCCaddr, assetoshis) == 0 )
else if( ConstrainVout(tx.vout[0], 1, origTokensCCaddr, assetoshis) == 0 ) // tokens returning to originator cc addr
return eval->Invalid("invalid vout for cancel");
preventCCvins = 3;
preventCCvouts = 1;
@@ -346,7 +368,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
//vout.3: normal output for change (if any)
//'S'.vout.n-1: opreturn [EVAL_ASSETS] ['S'] [assetid] [amount of coin still required] [origpubkey]
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 )
if( (assetoshis = AssetValidateSellvin(cpAssets, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 )
return(false);
else if( numvouts < 4 )
return eval->Invalid("not enough vouts for fillask");
@@ -358,21 +380,19 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
return eval->Invalid("locked value doesnt match vout0+1 fillask");
if( ValidateAskRemainder(remaining_price, tx.vout[0].nValue, assetoshis, tx.vout[1].nValue, tx.vout[2].nValue, totalunits) == false )
return eval->Invalid("mismatched remainder for fillask");
else if( ConstrainVout(tx.vout[1], 1, 0, 0) == 0 )
else if( ConstrainVout(tx.vout[1], 1, NULL, 0) == 0 ) // do not check token buyer's cc addr
return eval->Invalid("normal vout1 for fillask");
else if( ConstrainVout(tx.vout[2], 0, origaddr, 0) == 0 )
else if( ConstrainVout(tx.vout[2], 0, origNormalAddr, 0) == 0 ) // coins to originator normal addr
return eval->Invalid("normal vout1 for fillask");
else if( ConstrainVout(tx.vout[3], 1, origpubkeyCCaddr, 10000) == 0 )
else if( ConstrainVout(tx.vout[3], 1, origAssetsCCaddr, 10000) == 0 ) // marker to originator asset cc addr
return eval->Invalid("invalid marker for original pubkey");
else if( remaining_price != 0 )
{
//char tokensUnspendableAddr[64];
//GetTokensCCaddress(cpAssets, tokensUnspendableAddr, GetUnspendable(cpAssets, NULL));
if ( ConstrainVout(tx.vout[0], 1, tokensUnspendableAddr /*(char *)cpAssets->unspendableCCaddr*/, 0) == 0 )
if ( ConstrainVout(tx.vout[0], 1, tokensDualEvalUnspendableCCaddr, 0) == 0 )
return eval->Invalid("mismatched vout0 assets dual unspendable CCaddr for fill sell");
}
}
fprintf(stderr,"fill validated\n");
//fprintf(stderr,"fill validated\n");
break;
case 'E': // fillexchange
////////// not implemented yet ////////////
@@ -392,7 +412,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
// eval->Invalid("asset2 inputs != outputs");
////////// not implemented yet ////////////
if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, userTokensCCaddr, origaddr, tx, assetid)) == 0 )
if( (assetoshis= AssetValidateSellvin(cpTokens, eval, totalunits, tmporigpubkey, origTokensCCaddr, origNormalAddr, tx, assetid)) == 0 )
return(false);
else if( numvouts < 3 )
return eval->Invalid("not enough vouts for fillex");
@@ -405,7 +425,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
else if( tx.vout[3].scriptPubKey.IsPayToCryptoCondition() != 0 )
////////// not implemented yet ////////////
{
if( ConstrainVout(tx.vout[2], 1, userTokensCCaddr, 0) == 0 )
if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, 0) == 0 )
return eval->Invalid("vout2 doesnt go to origpubkey fillex");
else if( inputs != tx.vout[2].nValue + tx.vout[3].nValue )
{
@@ -414,7 +434,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
}
}
////////// not implemented yet ////////////
else if( ConstrainVout(tx.vout[2], 1, userTokensCCaddr, inputs) == 0 )
else if( ConstrainVout(tx.vout[2], 1, origTokensCCaddr, inputs) == 0 )
return eval->Invalid("vout2 doesnt match inputs fillex");
else if( ConstrainVout(tx.vout[1], 0, 0, 0) == 0 )
return eval->Invalid("vout1 is CC for fillex");
@@ -431,7 +451,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
}
}
////////// not implemented yet ////////////
fprintf(stderr,"fill validated\n");
//fprintf(stderr,"fill validated\n");
break;
default:
@@ -442,7 +462,7 @@ bool AssetsValidate(struct CCcontract_info *cpAssets,Eval* eval,const CTransacti
// what does this do?
bool bPrevent = PreventCC(eval, tx, preventCCvins, numvins, preventCCvouts, numvouts);
std::cerr << "AssetsValidate() PreventCC returned=" << bPrevent << std::endl;
//std::cerr << "AssetsValidate() PreventCC returned=" << bPrevent << std::endl;
return (bPrevent);
}

View File

@@ -28,25 +28,146 @@
#include "crosschain.h"
#define FAUCET2SIZE COIN
#define EVAL_FAUCET2 EVAL_FIRSTUSER
struct CClib_rpcinfo
{
char *method,*help;
int32_t numrequiredargs,maxargs; // frontloaded with required
uint8_t funcid;
}
CClib_methods[] =
{
{ (char *)"faucet2_fund", (char *)"amount", 1, 1, 'F' },
{ (char *)"faucet2_get", (char *)"<no args>", 0, 0, 'G' },
};
#ifdef BUILD_ROGUE
#define EVAL_ROGUE 17
std::string MYCCLIBNAME = (char *)"rogue";
#else
std::string MYCCLIBNAME = (char *)"faucet2";
#define EVAL_SUDOKU 17
std::string MYCCLIBNAME = (char *)"sudoku";
#endif
char *CClib_name() { return((char *)MYCCLIBNAME.c_str()); }
struct CClib_rpcinfo
{
char *CCname,*method,*help;
int32_t numrequiredargs,maxargs;
uint8_t funcid,evalcode;
}
CClib_methods[] =
{
{ (char *)"faucet2", (char *)"fund", (char *)"amount", 1, 1, 'F', EVAL_FAUCET2 },
{ (char *)"faucet2", (char *)"get", (char *)"<no args>", 0, 0, 'G', EVAL_FAUCET2 },
#ifdef BUILD_ROGUE
{ (char *)"rogue", (char *)"newgame", (char *)"maxplayers buyin", 0, 2, 'G', EVAL_ROGUE },
{ (char *)"rogue", (char *)"gameinfo", (char *)"gametxid", 1, 1, 'T', EVAL_ROGUE },
{ (char *)"rogue", (char *)"pending", (char *)"<no args>", 0, 0, 'P', EVAL_ROGUE },
{ (char *)"rogue", (char *)"register", (char *)"gametxid [playertxid]", 1, 2, 'R', EVAL_ROGUE },
{ (char *)"rogue", (char *)"keystrokes", (char *)"gametxid keystrokes", 2, 2, 'K', EVAL_ROGUE },
{ (char *)"rogue", (char *)"bailout", (char *)"gametxid", 1, 1, 'Q', EVAL_ROGUE },
{ (char *)"rogue", (char *)"highlander", (char *)"gametxid", 1, 1, 'H', EVAL_ROGUE },
{ (char *)"rogue", (char *)"playerinfo", (char *)"playertxid", 1, 1, 'I', EVAL_ROGUE },
{ (char *)"rogue", (char *)"players", (char *)"<no args>", 0, 0, 'D', EVAL_ROGUE },
{ (char *)"rogue", (char *)"games", (char *)"<no args>", 0, 0, 'F', EVAL_ROGUE },
{ (char *)"rogue", (char *)"setname", (char *)"pname", 1, 1, 'N', EVAL_ROGUE },
{ (char *)"rogue", (char *)"extract", (char *)"gametxid [pubkey]", 1, 2, 'X', EVAL_ROGUE },
#else
{ (char *)"sudoku", (char *)"gen", (char *)"<no args>", 0, 0, 'G', EVAL_SUDOKU },
{ (char *)"sudoku", (char *)"txidinfo", (char *)"txid", 1, 1, 'T', EVAL_SUDOKU },
{ (char *)"sudoku", (char *)"pending", (char *)"<no args>", 0, 0, 'U', EVAL_SUDOKU },
{ (char *)"sudoku", (char *)"solution", (char *)"txid solution timestamps[81]", 83, 83, 'S', EVAL_SUDOKU },
#endif
};
std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *params);
#ifdef BUILD_ROGUE
int32_t rogue_replay(uint64_t seed,int32_t sleeptime);
bool rogue_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
UniValue rogue_newgame(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_gameinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_register(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_keystrokes(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_bailout(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_highlander(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_playerinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_players(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_games(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_setname(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue rogue_extract(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
#else
bool sudoku_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const CTransaction tx);
UniValue sudoku_txidinfo(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue sudoku_generate(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue sudoku_solution(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
UniValue sudoku_pending(uint64_t txfee,struct CCcontract_info *cp,cJSON *params);
#endif
UniValue CClib_method(struct CCcontract_info *cp,char *method,cJSON *params)
{
UniValue result(UniValue::VOBJ); uint64_t txfee = 10000;
#ifdef BUILD_ROGUE
if ( cp->evalcode == EVAL_ROGUE )
{
if ( strcmp(method,"newgame") == 0 )
return(rogue_newgame(txfee,cp,params));
else if ( strcmp(method,"pending") == 0 )
return(rogue_pending(txfee,cp,params));
else if ( strcmp(method,"gameinfo") == 0 )
return(rogue_gameinfo(txfee,cp,params));
else if ( strcmp(method,"register") == 0 )
return(rogue_register(txfee,cp,params));
else if ( strcmp(method,"keystrokes") == 0 )
return(rogue_keystrokes(txfee,cp,params));
else if ( strcmp(method,"bailout") == 0 )
return(rogue_bailout(txfee,cp,params));
else if ( strcmp(method,"highlander") == 0 )
return(rogue_highlander(txfee,cp,params));
else if ( strcmp(method,"extract") == 0 )
return(rogue_extract(txfee,cp,params));
else if ( strcmp(method,"playerinfo") == 0 )
return(rogue_playerinfo(txfee,cp,params));
else if ( strcmp(method,"players") == 0 )
return(rogue_players(txfee,cp,params));
else if ( strcmp(method,"games") == 0 )
return(rogue_games(txfee,cp,params));
else if ( strcmp(method,"setname") == 0 )
return(rogue_setname(txfee,cp,params));
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid rogue method"));
result.push_back(Pair("method",method));
return(result);
}
}
#else
if ( cp->evalcode == EVAL_SUDOKU )
{
//printf("CClib_method params.%p\n",params);
if ( strcmp(method,"txidinfo") == 0 )
return(sudoku_txidinfo(txfee,cp,params));
else if ( strcmp(method,"gen") == 0 )
return(sudoku_generate(txfee,cp,params));
else if ( strcmp(method,"solution") == 0 )
return(sudoku_solution(txfee,cp,params));
else if ( strcmp(method,"pending") == 0 )
return(sudoku_pending(txfee,cp,params));
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","invalid sudoku method"));
result.push_back(Pair("method",method));
return(result);
}
}
#endif
else
{
result.push_back(Pair("result","error"));
result.push_back(Pair("error","only sudoku supported for now"));
result.push_back(Pair("evalcode",(int)cp->evalcode));
return(result);
}
}
UniValue CClib_info(struct CCcontract_info *cp)
{
UniValue result(UniValue::VOBJ),a(UniValue::VARR); int32_t i; char str[2];
@@ -55,6 +176,7 @@ UniValue CClib_info(struct CCcontract_info *cp)
for (i=0; i<sizeof(CClib_methods)/sizeof(*CClib_methods); i++)
{
UniValue obj(UniValue::VOBJ);
obj.push_back(Pair("evalcode",CClib_methods[i].evalcode));
if ( CClib_methods[i].funcid < ' ' || CClib_methods[i].funcid >= 128 )
obj.push_back(Pair("funcid",CClib_methods[i].funcid));
else
@@ -63,7 +185,8 @@ UniValue CClib_info(struct CCcontract_info *cp)
str[1] = 0;
obj.push_back(Pair("funcid",str));
}
obj.push_back(Pair("name",CClib_methods[i].method));
obj.push_back(Pair("name",CClib_methods[i].CCname));
obj.push_back(Pair("method",CClib_methods[i].method));
obj.push_back(Pair("help",CClib_methods[i].help));
obj.push_back(Pair("params_required",CClib_methods[i].numrequiredargs));
obj.push_back(Pair("params_max",CClib_methods[i].maxargs));
@@ -76,15 +199,19 @@ UniValue CClib_info(struct CCcontract_info *cp)
UniValue CClib(struct CCcontract_info *cp,char *method,cJSON *params)
{
UniValue result(UniValue::VOBJ); int32_t i; std::string rawtx;
//printf("CClib params.%p\n",params);
for (i=0; i<sizeof(CClib_methods)/sizeof(*CClib_methods); i++)
{
if ( strcmp(method,CClib_methods[i].method) == 0 )
if ( cp->evalcode == CClib_methods[i].evalcode && strcmp(method,CClib_methods[i].method) == 0 )
{
result.push_back(Pair("result","success"));
result.push_back(Pair("method",CClib_methods[i].method));
rawtx = CClib_rawtxgen(cp,CClib_methods[i].funcid,params);
result.push_back(Pair("rawtx",rawtx));
return(result);
if ( cp->evalcode == EVAL_FAUCET2 )
{
result.push_back(Pair("result","success"));
result.push_back(Pair("method",CClib_methods[i].method));
rawtx = CClib_rawtxgen(cp,CClib_methods[i].funcid,params);
result.push_back(Pair("rawtx",rawtx));
return(result);
} else return(CClib_method(cp,method,params));
}
}
result.push_back(Pair("result","error"));
@@ -93,12 +220,12 @@ UniValue CClib(struct CCcontract_info *cp,char *method,cJSON *params)
return(result);
}
int64_t IsCClibvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v)
int64_t IsCClibvout(struct CCcontract_info *cp,const CTransaction& tx,int32_t v,char *cmpaddr)
{
char destaddr[64];
if ( tx.vout[v].scriptPubKey.IsPayToCryptoCondition() != 0 )
{
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cp->unspendableCCaddr) == 0 )
if ( Getscriptaddress(destaddr,tx.vout[v].scriptPubKey) > 0 && strcmp(destaddr,cmpaddr) == 0 )
return(tx.vout[v].nValue);
}
return(0);
@@ -123,7 +250,7 @@ bool CClibExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
//fprintf(stderr,"vini.%d check hash and vout\n",i);
if ( hashBlock == zerohash )
return eval->Invalid("cant faucet2 from mempool");
if ( (assetoshis= IsCClibvout(cp,vinTx,tx.vin[i].prevout.n)) != 0 )
if ( (assetoshis= IsCClibvout(cp,vinTx,tx.vin[i].prevout.n,cp->unspendableCCaddr)) != 0 )
inputs += assetoshis;
}
}
@@ -131,7 +258,7 @@ bool CClibExactAmounts(struct CCcontract_info *cp,Eval* eval,const CTransaction
for (i=0; i<numvouts; i++)
{
//fprintf(stderr,"i.%d of numvouts.%d\n",i,numvouts);
if ( (assetoshis= IsCClibvout(cp,tx,i)) != 0 )
if ( (assetoshis= IsCClibvout(cp,tx,i,cp->unspendableCCaddr)) != 0 )
outputs += assetoshis;
}
if ( inputs != outputs+FAUCET2SIZE+txfee )
@@ -146,6 +273,14 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
if ( cp->evalcode != EVAL_FAUCET2 )
{
#ifdef BUILD_ROGUE
return(rogue_validate(cp,height,eval,tx));
#else
return(sudoku_validate(cp,height,eval,tx));
#endif
}
numvins = tx.vin.size();
numvouts = tx.vout.size();
preventCCvins = preventCCvouts = -1;
@@ -170,7 +305,7 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C
else
{
preventCCvouts = 1;
if ( IsCClibvout(cp,tx,0) != 0 )
if ( IsCClibvout(cp,tx,0,cp->unspendableCCaddr) != 0 )
{
preventCCvouts++;
i = 1;
@@ -202,9 +337,9 @@ bool CClib_validate(struct CCcontract_info *cp,int32_t height,Eval *eval,const C
}
}
int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs)
int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKey pk,int64_t total,int32_t maxinputs,char *cmpaddr)
{
char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
char coinaddr[64]; int64_t threshold,nValue,price,totalinputs = 0,txfee = 10000; uint256 txid,hashBlock; std::vector<uint8_t> origpubkey; CTransaction vintx; int32_t vout,n = 0;
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > unspentOutputs;
GetCCaddress(cp,coinaddr,pk);
SetCCunspents(unspentOutputs,coinaddr);
@@ -213,13 +348,13 @@ int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( it->second.satoshis < threshold )
//char str[65]; fprintf(stderr,"%s check %s/v%d %.8f vs %.8f\n",coinaddr,uint256_str(str,txid),vout,(double)it->second.satoshis/COIN,(double)threshold/COIN);
if ( it->second.satoshis < threshold || it->second.satoshis == txfee )
continue;
//char str[65]; fprintf(stderr,"check %s/v%d %.8f`\n",uint256_str(str,txid),vout,(double)it->second.satoshis/COIN);
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsCClibvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= IsCClibvout(cp,vintx,vout,cmpaddr)) >= 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -228,13 +363,12 @@ int64_t AddCClibInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
n++;
if ( (total > 0 && totalinputs >= total) || (maxinputs > 0 && n >= maxinputs) )
break;
} else fprintf(stderr,"nValue too small or already spent in mempool\n");
} //else fprintf(stderr,"nValue %.8f too small or already spent in mempool\n",(double)nValue/COIN);
} else fprintf(stderr,"couldnt get tx\n");
}
return(totalinputs);
}
std::string Faucet2Fund(struct CCcontract_info *cp,uint64_t txfee,int64_t funds)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -284,19 +418,19 @@ std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *para
return("");
cclibpk = GetUnspendable(cp,0);
mypk = pubkey2pk(Mypubkey());
if ( (inputs= AddCClibInputs(cp,mtx,cclibpk,nValue+txfee,60)) > 0 )
if ( (inputs= AddCClibInputs(cp,mtx,cclibpk,nValue+txfee,60,cp->unspendableCCaddr)) > 0 )
{
if ( inputs > nValue )
CCchange = (inputs - nValue - txfee);
if ( CCchange != 0 )
mtx.vout.push_back(MakeCC1vout(EVAL_FIRSTUSER,CCchange,cclibpk));
mtx.vout.push_back(MakeCC1vout(EVAL_FAUCET2,CCchange,cclibpk));
mtx.vout.push_back(CTxOut(nValue,CScript() << ParseHex(HexStr(mypk)) << OP_CHECKSIG));
fprintf(stderr,"start at %u\n",(uint32_t)time(NULL));
j = rand() & 0xfffffff;
for (i=0; i<1000000; i++,j++)
{
tmpmtx = mtx;
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_FIRSTUSER << (uint8_t)'G' << j));
rawhex = FinalizeCCTx(-1LL,cp,tmpmtx,mypk,txfee,CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_FAUCET2 << (uint8_t)'G' << j));
if ( (len= (int32_t)rawhex.size()) > 0 && len < 65536 )
{
len >>= 1;
@@ -315,3 +449,88 @@ std::string CClib_rawtxgen(struct CCcontract_info *cp,uint8_t funcid,cJSON *para
} else fprintf(stderr,"cant find faucet inputs\n");
return("");
}
UniValue cclib_error(UniValue &result,const char *errorstr)
{
result.push_back(Pair("status","error"));
result.push_back(Pair("error",errorstr));
return(result);
}
uint256 juint256(cJSON *obj)
{
uint256 tmp; bits256 t = jbits256(obj,0);
memcpy(&tmp,&t,sizeof(tmp));
return(revuint256(tmp));
}
cJSON *cclib_reparse(int32_t *nump,cJSON *origparams) // assumes origparams will be freed by caller
{
cJSON *params; char *jsonstr,*newstr; int32_t i,j;
if ( (jsonstr= jprint(origparams,0)) != 0 )
{
if ( jsonstr[0] == '"' && jsonstr[strlen(jsonstr)-1] == '"' )
{
jsonstr[strlen(jsonstr)-1] = 0;
jsonstr++;
}
newstr = (char *)malloc(strlen(jsonstr)+1);
for (i=j=0; jsonstr[i]!=0; i++)
{
if ( jsonstr[i] == '%' && jsonstr[i+1] == '2' && jsonstr[i+2] == '2' )
{
newstr[j++] = '"';
i += 2;
} else newstr[j++] = jsonstr[i];
}
newstr[j] = 0;
params = cJSON_Parse(newstr);
if ( 0 && params != 0 )
printf("new.(%s) -> %s\n",newstr,jprint(params,0));
free(newstr);
*nump = cJSON_GetArraySize(params);
//free(origparams);
} else params = 0;
return(params);
}
#ifdef BUILD_ROGUE
#include "rogue_rpc.cpp"
#include "rogue/vers.c"
#include "rogue/extern.c"
#include "rogue/armor.c"
#include "rogue/chase.c"
#include "rogue/command.c"
#include "rogue/daemon.c"
#include "rogue/daemons.c"
#include "rogue/fight.c"
#include "rogue/init.c"
#include "rogue/io.c"
#include "rogue/list.c"
#include "rogue/mach_dep.c"
#include "rogue/rogue.c"
#include "rogue/xcrypt.c"
#include "rogue/mdport.c"
#include "rogue/misc.c"
#include "rogue/monsters.c"
#include "rogue/move.c"
#include "rogue/new_level.c"
#include "rogue/options.c"
#include "rogue/pack.c"
#include "rogue/passages.c"
#include "rogue/potions.c"
#include "rogue/rings.c"
#include "rogue/rip.c"
#include "rogue/rooms.c"
#include "rogue/save.c"
#include "rogue/scrolls.c"
#include "rogue/state.c"
#include "rogue/sticks.c"
#include "rogue/things.c"
#include "rogue/weapons.c"
#include "rogue/wizard.c"
#else
#include "sudoku.cpp"
#endif

View File

@@ -106,12 +106,12 @@ CScript EncodeChannelsOpRet(uint8_t funcid,uint256 tokenid,uint256 opentxid,CPub
uint8_t DecodeChannelsOpRet(const CScript &scriptPubKey, uint256 &tokenid, uint256 &opentxid, CPubKey &srcpub,CPubKey &destpub,int32_t &numpayments,int64_t &payment,uint256 &hashchain)
{
std::vector<uint8_t> vopret; uint8_t *script,e,f,tokenevalcode;
std::vector<CPubKey> pubkeys; std::vector<uint8_t> vOpretExtra;
std::vector<uint8_t> vopret,vOpretExtra; uint8_t *script,e,f,tokenevalcode;
std::vector<CPubKey> pubkeys;
if (DecodeTokenOpRet(scriptPubKey,tokenevalcode,tokenid,pubkeys,vOpretExtra)!=0 && tokenevalcode==EVAL_TOKENS && vOpretExtra.size()>0)
{
if (!E_UNMARSHAL(vOpretExtra, { ss >> vopret; })) return (0);
vopret=vOpretExtra;
}
else GetOpReturnData(scriptPubKey, vopret);
if ( vopret.size() > 2 )
@@ -430,7 +430,7 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C
}
}
}
if (txid!=zeroid && myIsutxo_spentinmempool(txid,0) != 0)
if (txid!=zeroid && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,0) != 0)
{
txid=zeroid;
int32_t mindepth=CHANNELS_MAXPAYMENTS;
@@ -455,7 +455,7 @@ int64_t AddChannelsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx, C
mtx.vin.push_back(CTxIn(txid,marker,CScript()));
Myprivkey(myprivkey);
if (tokenid!=zeroid) CCaddrTokens1of2set(cp,srcpub,destpub,coinaddr);
else CCaddr1of2set(cp,srcpub,destpub,coinaddr);
else CCaddr1of2set(cp,srcpub,destpub,myprivkey,coinaddr);
return totalinputs;
}
else return 0;

View File

@@ -236,7 +236,7 @@ void *loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep)
{
fclose(fp);
*lenp = 0;
printf("loadfile null size.(%s)\n",fname);
//printf("loadfile null size.(%s)\n",fname);
return(0);
}
if ( filesize > buflen )
@@ -312,22 +312,20 @@ uint64_t get_btcusd()
char *REFCOIN_CLI;
cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3)
cJSON *get_cli(char *refcoin,char **retstrp,char *acname,char *method,char *arg0,char *arg1,char *arg2,char *arg3)
{
long fsize; cJSON *retjson = 0; char cmdstr[32768],*jsonstr,fname[256];
sprintf(fname,"/tmp/oraclefeed.%s",method);
if ( acname[0] != 0 )
{
if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 )
printf("unexpected: refcoin.(%s) acname.(%s)\n",refcoin,acname);
sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s %s > %s\n",acname,method,arg0,arg1,arg2,arg3,fname);
if ( refcoin[0] == 0 )
printf("must supply reference coin\n");
sprintf(cmdstr,"./komodo-cli -ac_name=%s %s %s %s %s %s > %s 2>/tmp/oraclefeed.error\n",acname,method,arg0,arg1,arg2,arg3,fname);
}
else if ( strcmp(refcoin,"KMD") == 0 )
sprintf(cmdstr,"./komodo-cli %s %s %s %s %s > %s\n",method,arg0,arg1,arg2,arg3,fname);
else if ( REFCOIN_CLI != 0 && REFCOIN_CLI[0] != 0 )
{
sprintf(cmdstr,"%s %s %s %s %s %s > %s\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,fname);
printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr);
sprintf(cmdstr,"%s %s %s %s %s %s > %s 2>/tmp/oraclefeed.error\n",REFCOIN_CLI,method,arg0,arg1,arg2,arg3,fname);
//printf("ref.(%s) REFCOIN_CLI (%s)\n",refcoin,cmdstr);
}
#ifdef TESTMODE
fprintf(stderr,"cmd: %s\n",cmdstr);
@@ -340,22 +338,24 @@ cJSON *get_komodocli(char *refcoin,char **retstrp,char *acname,char *method,char
#ifdef TESTMODE
fprintf(stderr,"jsonstr.(%s)\n",jsonstr);
#endif // TESTMODE
if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0 )
if ( (jsonstr[0] != '{' && jsonstr[0] != '[') || (retjson= cJSON_Parse(jsonstr)) == 0)
*retstrp = jsonstr;
else free(jsonstr);
}
else if ( (jsonstr= filestr(&fsize,"/tmp/oraclefeed.error")) != 0 )
*retstrp = jsonstr;
return(retjson);
}
bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson)
bits256 broadcasttx(char *refcoin,char *acname,cJSON *hexjson)
{
char *hexstr,*retstr,str[65]; cJSON *retjson; bits256 txid;
memset(txid.bytes,0,sizeof(txid));
if ( (hexstr= jstr(hexjson,"hex")) != 0 )
{
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"sendrawtransaction",hexstr,"","","")) != 0 )
{
//fprintf(stderr,"broadcast.(%s)\n",jprint(retjson,0));
if (strcmp("error",jstr(retjson,"result"))==0) printf("%s\n",jstr(retjson,"error"));
free_json(retjson);
}
else if ( retstr != 0 )
@@ -372,36 +372,14 @@ bits256 komodobroadcast(char *refcoin,char *acname,cJSON *hexjson)
return(txid);
}
bits256 sendtoaddress(char *refcoin,char *acname,char *destaddr,int64_t satoshis)
{
char numstr[32],*retstr,str[65]; cJSON *retjson; bits256 txid;
memset(txid.bytes,0,sizeof(txid));
sprintf(numstr,"%.8f",(double)satoshis/SATOSHIDEN);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"sendtoaddress",destaddr,numstr,"","")) != 0 )
{
fprintf(stderr,"unexpected sendrawtransaction json.(%s)\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
if ( strlen(retstr) >= 64 )
{
retstr[64] = 0;
decode_hex(txid.bytes,32,retstr);
}
fprintf(stderr,"sendtoaddress %s %.8f txid.(%s)\n",destaddr,(double)satoshis/SATOSHIDEN,bits256_str(str,txid));
free(retstr);
}
return(txid);
}
int32_t get_coinheight(char *refcoin,char *acname)
{
cJSON *retjson; char *retstr; int32_t height=0;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockchaininfo","","","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getblockchaininfo","","","","")) != 0 )
{
height = jint(retjson,"blocks");
free_json(retjson);
}
else if ( retstr != 0 )
{
@@ -416,7 +394,7 @@ bits256 get_coinblockhash(char *refcoin,char *acname,int32_t height)
cJSON *retjson; char *retstr,heightstr[32]; bits256 hash;
memset(hash.bytes,0,sizeof(hash));
sprintf(heightstr,"%d",height);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getblockhash",heightstr,"","","")) != 0 )
{
fprintf(stderr,"unexpected blockhash json.(%s)\n",jprint(retjson,0));
free_json(retjson);
@@ -437,7 +415,7 @@ bits256 get_coinmerkleroot(char *refcoin,char *acname,bits256 blockhash)
{
cJSON *retjson; char *retstr,str[65]; bits256 merkleroot;
memset(merkleroot.bytes,0,sizeof(merkleroot));
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getblockheader",bits256_str(str,blockhash),"","","")) != 0 )
{
merkleroot = jbits256(retjson,"merkleroot");
//fprintf(stderr,"got merkleroot.(%s)\n",bits256_str(str,merkleroot));
@@ -475,7 +453,7 @@ int32_t get_coinheader(char *refcoin,char *acname,bits256 *blockhashp,bits256 *m
cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspending",bindtxidstr,refcoin,"","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewayspendingwithdraws",bindtxidstr,refcoin,"","")) != 0 )
{
//printf("pending.(%s)\n",jprint(retjson,0));
return(retjson);
@@ -491,7 +469,7 @@ cJSON *get_gatewayspending(char *refcoin,char *acname,char *bindtxidstr)
cJSON *get_gatewaysprocessed(char *refcoin,char *acname,char *bindtxidstr)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysprocessed",bindtxidstr,refcoin,"","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewaysprocessed",bindtxidstr,refcoin,"","")) != 0 )
{
//printf("pending.(%s)\n",jprint(retjson,0));
return(retjson);
@@ -507,7 +485,7 @@ cJSON *get_gatewaysprocessed(char *refcoin,char *acname,char *bindtxidstr)
cJSON *get_rawmempool(char *refcoin,char *acname)
{
cJSON *retjson; char *retstr;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawmempool","","","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getrawmempool","","","","")) != 0 )
{
//printf("mempool.(%s)\n",jprint(retjson,0));
return(retjson);
@@ -526,14 +504,14 @@ cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr)
if ( refcoin[0] != 0 && strcmp(refcoin,"KMD") != 0 )
printf("warning: assumes %s has addressindex enabled\n",refcoin);
sprintf(jsonbuf,"{\\\"addresses\\\":[\\\"%s\\\"]}",coinaddr);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getaddressutxos",jsonbuf,"","","")) != 0 )
{
//printf("addressutxos.(%s)\n",jprint(retjson,0));
return(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr);
//fprintf(stderr,"get_addressutxos.(%s) error.(%s)\n",acname,retstr);
free(retstr);
}
return(0);
@@ -542,7 +520,7 @@ cJSON *get_addressutxos(char *refcoin,char *acname,char *coinaddr)
cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid)
{
cJSON *retjson; char *retstr,str[65];
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"getrawtransaction",bits256_str(str,txid),"1","","")) != 0 )
{
return(retjson);
}
@@ -557,7 +535,7 @@ cJSON *get_rawtransaction(char *refcoin,char *acname,bits256 txid)
int32_t validateaddress(char *refcoin,char *acname,char *depositaddr, char* compare)
{
cJSON *retjson; char *retstr; int32_t res=0;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"validateaddress",depositaddr,"","","")) != 0 )
{
if (is_cJSON_True(jobj(retjson,compare)) != 0 ) res=1;
free_json(retjson);
@@ -576,7 +554,7 @@ void importaddress(char *refcoin,char *acname,char *depositaddr, char *label,int
cJSON *retjson; char *retstr; char rescanstr[10];
if (rescan) strcpy(rescanstr,"true");
else strcpy(rescanstr,"false");
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"importaddress",depositaddr,label,rescanstr,"")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"importaddress",depositaddr,label,rescanstr,"")) != 0 )
{
printf("importaddress.(%s)\n",jprint(retjson,0));
free_json(retjson);
@@ -588,19 +566,20 @@ void importaddress(char *refcoin,char *acname,char *depositaddr, char *label,int
}
}
void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys,char *bindtxidstr)
void addmultisigaddress(char *refcoin,char *acname,int32_t M, char *pubkeys)
{
cJSON *retjson; char *retstr,Mstr[10],tmp[128];
cJSON *retjson; char *retstr,Mstr[10],addr[64];
sprintf(Mstr,"%d",M);
sprintf(tmp,"\"%s\"",bindtxidstr);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,tmp,"")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"addmultisigaddress",Mstr,pubkeys,"","")) != 0 )
{
fprintf(stderr,"unexpected addmultisigaddress json.(%s)\n",jprint(retjson,0));
free(retstr);
}
else if ( retstr != 0 )
{
sprintf(addr,"\"%s\"",retstr);
get_cli(refcoin,&retstr,acname,"importaddress",addr,"\"\"","false","");
printf("addmultisigaddress.(%s)\n",retstr);
free_json(retjson);
}
@@ -641,12 +620,11 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
else txfee = 10000;
if ( satoshis < txfee )
{
printf("createrawtx satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN);
printf("createrawtx: satoshis %.8f < txfee %.8f\n",(double)satoshis/SATOSHIDEN,(double)txfee/SATOSHIDEN);
return(0);
}
satoshis -= txfee;
sprintf(array,"\'[\"%s\"]\'",depositaddr);
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"listunspent","1","99999999",array,"")) != 0 )
{
//createrawtransaction [{"txid":"id","vout":n},...] {"address":amount,...}
if ( (vins= getinputarray(&total,retjson,satoshis)) != 0 )
@@ -667,7 +645,7 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
char *argB=malloc(sizeof(char) * (strlen(tmpB)+3));
sprintf(argA,"\'%s\'",tmpA);
sprintf(argB,"\'%s\'",tmpB);
if ( (retjson2= get_komodocli(refcoin,&txstr,acname,"createrawtransaction",argA,argB,"","")) != 0 )
if ( (retjson2= get_cli(refcoin,&txstr,acname,"createrawtransaction",argA,argB,"","")) != 0 )
{
printf("createrawtx: unexpected JSON2.(%s)\n",jprint(retjson2,0));
free_json(retjson2);
@@ -680,7 +658,7 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
free(argB);
}
else printf("not enough funds to create withdraw tx\n");
}
}
free_json(retjson);
}
else if ( retstr != 0 )
@@ -692,14 +670,14 @@ char *createrawtx(char *refcoin,char *acname,char *depositaddr,char *withdrawadd
return(txstr);
}
cJSON *addsignature(char *refcoin,char *acname,char *rawtx)
cJSON *addsignature(char *refcoin,char *acname,char *rawtx, int M)
{
char *retstr,*hexstr; cJSON *retjson;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"signrawtransaction",rawtx,"","","")) != 0 )
{
if ( is_cJSON_True(jobj(retjson,"complete")) != 0 )
return(retjson);
else if ( (hexstr= jstr(retjson,"hex")) != 0 && strlen(hexstr) > strlen(rawtx) )
else if ((hexstr=jstr(retjson,"hex"))!= 0 && strlen(hexstr) > strlen(rawtx) + (M*2) + 1)
{
jaddnum(retjson,"partialtx",1);
return(retjson);
@@ -714,32 +692,15 @@ cJSON *addsignature(char *refcoin,char *acname,char *rawtx)
return(0);
}
char *get_gatewaysmultisig(char *refcoin,char *acname,char *txidaddr,int32_t *K)
{
char *retstr,*hexstr,*hex=0; cJSON *retjson;
if ( (retjson= get_komodocli("KMD",&retstr,acname,"gatewaysmultisig",txidaddr,"","","")) != 0 )
{
if ((hexstr=jstr(retjson,"hex")) != 0 )
{
if (strlen(hexstr)>0) hex = clonestr(hexstr);
}
*K=jint(retjson,"number_of_signs");
free_json(retjson);
}
else if ( retstr != 0 )
{
printf("error parsing gatewaysmultisig.(%s)\n",retstr);
free(retstr);
}
return(hex);
}
bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex)
{
char str[65],*retstr; cJSON *retjson;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),refcoin,hex,"")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewayspartialsign",bits256_str(str,txid),refcoin,hex,"")) != 0 )
{
return(komodobroadcast(refcoin,acname,retjson));
if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson);
else printf("%s\n",jstr(retjson,"error"));
free(retjson);
return (txid);
}
else if ( retstr != 0 )
{
@@ -749,42 +710,46 @@ bits256 gatewayspartialsign(char *refcoin,char *acname,bits256 txid,char *hex)
return (zeroid);
}
void gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char *coin,char *hex)
bits256 gatewayscompletesigning(char *refcoin,char *acname,bits256 withtxid,char *hex)
{
char str[65],str2[65],*retstr; cJSON *retjson;
printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid));
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewayscompletesigning",bits256_str(str,withtxid),coin,hex,"")) != 0 )
char str[65],*retstr; cJSON *retjson; bits256 txid;
if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewayscompletesigning",bits256_str(str,withtxid),refcoin,hex,"")) != 0 )
{
komodobroadcast(refcoin,acname,retjson);
free_json(retjson);
if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson);
else printf("%s\n",jstr(retjson,"error"));
free(retjson);
return (txid);
}
else if ( retstr != 0 )
{
printf("error parsing gatewayscompletesigning.(%s)\n",retstr);
free(retstr);
}
return (zeroid);
}
void gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid,char *coin)
bits256 gatewaysmarkdone(char *refcoin,char *acname,bits256 withtxid)
{
char str[65],str2[65],*retstr; cJSON *retjson;
printf("spend %s %s/v2 as marker\n",acname,bits256_str(str,withtxid));
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),coin,"","")) != 0 )
char str[65],str2[65],*retstr; cJSON *retjson; bits256 txid;
if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewaysmarkdone",bits256_str(str,withtxid),refcoin,"","")) != 0 )
{
komodobroadcast(refcoin,acname,retjson);
free_json(retjson);
if (strcmp("error",jstr(retjson,"result"))!=0) txid=broadcasttx(refcoin,acname,retjson);
else printf("%s\n",jstr(retjson,"error"));
free(retjson);
return (txid);
}
else if ( retstr != 0 )
{
printf("error parsing gatewaysmarkdone.(%s)\n",retstr);
free(retstr);
}
return (zeroid);
}
int32_t get_gatewaysinfo(char *refcoin,char *acname,char *depositaddr,int32_t *Mp,int32_t *Np,char *bindtxidstr,char *coin,char *oraclestr, char **pubkeys)
{
char *oracle,*retstr,*name,*deposit,temp[128]; cJSON *retjson,*pubarray; int32_t n;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"gatewaysinfo",bindtxidstr,"","","")) != 0 )
if ( (retjson= get_cli(refcoin,&retstr,acname,"gatewaysinfo",bindtxidstr,"","","")) != 0 )
{
if ( (oracle= jstr(retjson,"oracletxid")) != 0 && strcmp(oracle,oraclestr) == 0 && (deposit= jstr(retjson,"deposit")) != 0 )
{
@@ -882,55 +847,9 @@ int32_t markerexists(char *refcoin,char *acname,char *coinaddr)
free_json(array);
}
}
fprintf(stderr,"Num=%d\n",num);
return(num);
}
int32_t markerfromthisnodeorunconfirmed(char *refcoin,char *acname,char *coinaddr)
{
cJSON *array,*item,*rawtx,*vins,*vin; bits256 txid,tmptxid; int32_t i,n,m,num=0; char *retstr;
if ( (array= get_addressutxos(refcoin,acname,coinaddr)) != 0 )
{
n=cJSON_GetArraySize(array);
for (i=0; i<n; i++)
{
if ((item=jitem(array,i))!=0 && (bits256_nonz(tmptxid=jbits256(item,"txid")))!=0 && (rawtx=get_rawtransaction(refcoin,acname,tmptxid))!=0 && (vins=jarray(&m,rawtx,"vin"))!=0)
{
for (int j=0;j<m;j++)
{
if ((vin=jitem(vins,j))!=0 && validateaddress(refcoin,acname,jstr(vin,"address"),"ismine")!=0)
{
num=1;
break;
}
}
}
if (num==1) break;
}
free_json(array);
}
else return(-1);
if ( num == 0 )
{
if ( (array= get_rawmempool(refcoin,acname)) != 0 )
{
if ( (n= cJSON_GetArraySize(array)) != 0 )
{
for (i=0; i<n; i++)
{
txid = jbits256i(array,i);
if ( tx_has_voutaddress(refcoin,acname,txid,coinaddr) > 0 )
{
num = 1;
break;
}
}
}
free_json(array);
} else return(-1);
}
return(num);
}
void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t M,int32_t N)
{
@@ -941,9 +860,11 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t
/// if enough sigs, sendrawtransaction and when it confirms spend marker (txid.2)
/// if not enough sigs, post partially signed to acname with marker2
// monitor marker2, for the partially signed withdraws
cJSON *retjson,*pending,*item,*clijson; char str[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr; int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,origtxid; int64_t satoshis;
cJSON *retjson,*pending,*item,*clijson; char str[65],str1[65],str2[65],*rawtx,*coinstr,*txidaddr,*signeraddr,*depositaddr,*withdrawaddr;
int32_t i,j,n,K,retval,processed = 0; bits256 txid,cointxid,withdrawtxid,lasttxid,completetxid; int64_t satoshis;
memset(&zeroid,0,sizeof(zeroid));
if ( (retjson= get_gatewayspending("KMD",acname,bindtxidstr)) != 0 )
if ( (retjson= get_gatewayspending(refcoin,acname,bindtxidstr)) != 0 )
{
if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 )
{
@@ -954,86 +875,95 @@ void update_gatewayspending(char *refcoin,char *acname,char *bindtxidstr,int32_t
if ( processed != 0 ) // avoid out of utxo conditions
break;
item = jitem(pending,i);
origtxid = jbits256(item,"txid");
withdrawtxid = jbits256(item,"withdrawtxid");
//process item.0 {"txid":"10ec8f4dad6903df6b249b361b879ac77b0617caad7629b97e10f29fa7e99a9b","txidaddr":"RMbite4TGugVmkGmu76ytPHDEQZQGSUjxz","withdrawaddr":"RNJmgYaFF5DbnrNUX6pMYz9rcnDKC2tuAc","amount":"1.00000000","depositaddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj","signeraddr":"RHV2As4rox97BuE3LK96vMeNY8VsGRTmBj"}
if ( (txidaddr= jstr(item,"txidaddr")) != 0 && (withdrawaddr= jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 )
if ( (txidaddr=jstr(item,"withdrawtxidaddr"))!= 0 && (withdrawaddr=jstr(item,"withdrawaddr")) != 0 && (depositaddr= jstr(item,"depositaddr")) != 0 && (signeraddr= jstr(item,"signeraddr")) != 0 )
{
if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0 && markerfromthisnodeorunconfirmed("KMD",acname,txidaddr) == 0)
if ( (satoshis= jdouble(item,"amount")*SATOSHIDEN) != 0 && is_cJSON_True(jobj(item,"confirmed_or_notarized")) != 0)
{
if ( strcmp(depositaddr,signeraddr) == 0 )
{
rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis);
if ( rawtx != 0 )
{
if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0)
if ( (clijson=addsignature(refcoin,"",rawtx,M)) != 0 && is_cJSON_True(jobj(clijson,"complete")) != 0)
{
gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex"));
fprintf(stderr,"withdraw %.8f %s to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,withdrawaddr);
txid=gatewayscompletesigning(refcoin,acname,withdrawtxid,jstr(clijson,"hex"));
if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s 1of1\n",bits256_str(str,withdrawtxid));
else fprintf(stderr,"### SIGNING error broadcasting tx on %s",acname);
free_json(clijson);
}
processed++;
processed++;
}
free(rawtx);
} else fprintf(stderr,"couldnt create rawtx\n");
}
else
{
if ( (rawtx= get_gatewaysmultisig(refcoin,acname,txidaddr,&K)) == 0)
lasttxid = jbits256(item,"last_txid");
if ( lasttxid.txid==withdrawtxid.txid)
{
rawtx = createrawtx(refcoin,"",depositaddr,withdrawaddr,txidaddr,satoshis);
}
if ( rawtx != 0 )
else rawtx=jstr(item,"hex");
K=jint(item,"number_of_signs");
if ( rawtx!=0 && (clijson=addsignature(refcoin,"",rawtx,M)) != 0 )
{
if ( (clijson= addsignature(refcoin,"",rawtx)) != 0 )
{
if ( is_cJSON_True(jobj(clijson,"complete")) != 0 )
{
gatewayscompletesigning("KMD",acname,origtxid,refcoin,jstr(clijson,"hex"));
fprintf(stderr,"withdraw %.8f %s M.%d N.%d to %s processed\n",(double)satoshis/SATOSHIDEN,refcoin,M,N,withdrawaddr);
}
else if ( jint(clijson,"partialtx") != 0 )
{
txid=gatewayspartialsign(refcoin,acname,origtxid,jstr(clijson,"hex"));
fprintf(stderr,"%d sign(s) %dof%d partialtx %s sent\n",K+1,M,N,bits256_str(str,txid));
}
free_json(clijson);
if ( is_cJSON_True(jobj(clijson,"complete")) != 0 )
{
txid=gatewayscompletesigning(refcoin,acname,lasttxid,jstr(clijson,"hex"));
if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %dof%d\n",bits256_str(str,withdrawtxid),K+1,N);
else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname);
}
else if ( jint(clijson,"partialtx") != 0 )
{
txid=gatewayspartialsign(refcoin,acname,lasttxid,jstr(clijson,"hex"));
if (txid.txid!=zeroid.txid) fprintf(stderr,"### SIGNING withdraw %s %d/%dof%d\n",bits256_str(str,withdrawtxid),K+1,M,N);
else fprintf(stderr,"### SIGNING error broadcasting tx on %s\n",acname);
}
free_json(clijson);
processed++;
free(rawtx);
} else fprintf(stderr,"couldnt create msig rawtx\n");
}
}
if ( lasttxid.txid==withdrawtxid.txid) free(rawtx);
}
}
}
}
}
}
}
free_json(retjson);
}
if ( (retjson= get_gatewaysprocessed("KMD",acname,bindtxidstr)) != 0 )
if ( (retjson= get_gatewaysprocessed(refcoin,acname,bindtxidstr)) != 0 )
{
if ( jint(retjson,"queueflag") != 0 && (coinstr= jstr(retjson,"coin")) != 0 && strcmp(coinstr,refcoin) == 0 )
{
if ( (pending=jarray(&n,retjson,"processed")) != 0 )
if ((pending=jarray(&n,retjson,"processed")) != 0)
{
for (i=0; i<n; i++)
{
item = jitem(pending,i);
origtxid = jbits256(item,"txid");
completetxid = jbits256(item,"completesigningtxid");
txidaddr = jstr(item,"withdrawtxidaddr");
withdrawtxid= jbits256(item,"withdrawtxid");
double amount = jdouble(item,"amount");
if (validateaddress(refcoin,"",txidaddr,"iswatchonly")==0 && validateaddress(refcoin,"",txidaddr,"ismine")==0)
importaddress(refcoin,"",txidaddr,jstr(item,"txid"),0);
if ( txidaddr != 0 && markerexists(refcoin,"",txidaddr)==0)
importaddress(refcoin,"",txidaddr,jstr(item,"withdrawtxid"),0);
if (is_cJSON_True(jobj(item,"confirmed_or_notarized")) && txidaddr != 0 && markerexists(refcoin,"",txidaddr)==0)
{
cointxid = komodobroadcast(refcoin,"",item);
cointxid = broadcasttx(refcoin,"",item);
if ( bits256_nonz(cointxid) != 0 )
{
withdrawaddr = jstr(item,"withdrawaddr");
fprintf(stderr,"withdraw %.8f %s to %s - %s broadcasted on %s\n",(double)satoshis/SATOSHIDEN,refcoin,withdrawaddr,bits256_str(str,cointxid),refcoin);
gatewaysmarkdone("KMD",acname,origtxid,refcoin);
withdrawaddr = jstr(item,"withdrawaddr");
fprintf(stderr,"### WITHDRAW %.8f %s sent to %s\n",amount,refcoin,withdrawaddr);
txid=gatewaysmarkdone(refcoin,acname,completetxid);
if (txid.txid!=zeroid.txid) fprintf(stderr,"### MARKDONE withdraw %s\n",bits256_str(str,withdrawtxid));
else fprintf(stderr,"### MARKDONE error broadcasting tx on %s\n",refcoin);
}
else fprintf(stderr,"### WITHDRAW error broadcasting tx on %s\n",refcoin);
}
}
}
}
free_json(retjson);
}
}
@@ -1120,7 +1050,7 @@ int32_t main(int32_t argc,char **argv)
while ( 1 )
{
retstr = 0;
if ( (refcoin[0] == 0 || prevheight < (get_coinheight(refcoin,"") - 10)) && (clijson= get_komodocli("KMD",&retstr,acname,"oraclesinfo",oraclestr,"","","")) != 0 )
if ( (refcoin[0] == 0 || prevheight < (get_coinheight(refcoin,"") - 10)) && (clijson= get_cli(refcoin,&retstr,acname,"oraclesinfo",oraclestr,"","","")) != 0 )
{
if ( refcoin[0] == 0 && jstr(clijson,"name") != 0 )
{
@@ -1131,15 +1061,15 @@ int32_t main(int32_t argc,char **argv)
exit(0);
}
pubkeys=0;
if ( get_gatewaysinfo("KMD",acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) < 0 )
if ( get_gatewaysinfo(refcoin,acname,depositaddr,&M,&N,bindtxidstr,refcoin,oraclestr,&pubkeys) < 0 )
{
printf("cant find bindtxid.(%s)\n",bindtxidstr);
exit(0);
}
if (validateaddress(refcoin,"",depositaddr,"iswatchonly")==0 && validateaddress(refcoin,"",depositaddr,"ismine")==0)
{
if (M==N==1) importaddress(refcoin,"",depositaddr,bindtxidstr,0);
else addmultisigaddress(refcoin,"",M,pubkeys,bindtxidstr);
if (M==1 && N==1) importaddress(refcoin,"",depositaddr,bindtxidstr,0);
else addmultisigaddress(refcoin,"",M,pubkeys);
}
if (pubkeys!=0) free(pubkeys);
printf("set refcoin %s <- %s [%s] M.%d of N.%d\n",depositaddr,refcoin,REFCOIN_CLI,M,N);
@@ -1153,10 +1083,9 @@ int32_t main(int32_t argc,char **argv)
{
if ( (height= get_oracledata(refcoin,"",prevheight,hexstr,sizeof(hexstr),"Ihh")) != 0 )
{
if ( (clijson2= get_komodocli("KMD",&retstr2,acname,"oraclesdata",oraclestr,hexstr,"","")) != 0 )
if ( (clijson2= get_cli(refcoin,&retstr2,acname,"oraclesdata",oraclestr,hexstr,"","")) != 0 )
{
//printf("data.(%s)\n",jprint(clijson2,0));
txid = komodobroadcast("KMD",acname,clijson2);
txid = broadcasttx(refcoin,acname,clijson2);
if ( bits256_nonz(txid) != 0 )
{
prevheight = height;

View File

@@ -700,23 +700,6 @@ int32_t z_getnewaddress(char *coinaddr,char *refcoin,char *acname,char *typestr)
return(retval);
}
int32_t z_getnewaddress(char *coinaddr,char *refcoin,char *acname,char *typestr)
{
cJSON *retjson; char *retstr; int64_t amount=0;
if ( (retjson= get_komodocli(refcoin,&retstr,acname,"z_getnewaddress",typestr,"","","")) != 0 )
{
fprintf(stderr,"z_getnewaddress.(%s) %s returned json!\n",refcoin,acname);
free_json(retjson);
return(-1);
}
else if ( retstr != 0 )
{
strcpy(coinaddr,retstr);
free(retstr);
return(0);
}
}
int64_t find_onetime_amount(char *coinstr,char *coinaddr)
{
cJSON *array,*item; int32_t i,n; char *addr; int64_t amount = 0;
@@ -812,53 +795,8 @@ int32_t z_mergetoaddress(char *opidstr,char *coinstr,char *acname,char *destaddr
{
cJSON *retjson; char *retstr,addr[128],*opstr; int32_t retval = -1;
sprintf(addr,"[\\\"ANY_SPROUT\\\"]");
//printf("z_sendmany from.(%s) -> %s\n",addr,destaddr);
if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_mergetoaddress",addr,destaddr,"","")) != 0 )
{
/*{
"remainingUTXOs": 0,
"remainingTransparentValue": 0.00000000,
"remainingNotes": 222,
"remainingShieldedValue": 5413.39093055,
"mergingUTXOs": 0,
"mergingTransparentValue": 0.00000000,
"mergingNotes": 10,
"mergingShieldedValue": 822.47447172,
"opid": "opid-f28f6261-4120-436c-aca5-859870a40a70"
}*/
if ( (opstr= jstr(retjson,"opid")) != 0 )
strcpy(opidstr,opstr);
retval = jint(retjson,"remainingNotes");
fprintf(stderr,"%s\n",jprint(retjson,0));
free_json(retjson);
}
else if ( retstr != 0 )
{
fprintf(stderr,"z_mergetoaddress.(%s) -> opid.(%s)\n",coinstr,retstr);
strcpy(opidstr,retstr);
free(retstr);
}
return(retval);
}
int32_t z_mergetoaddress(char *opidstr,char *coinstr,char *acname,char *destaddr)
{
cJSON *retjson; char *retstr,addr[128],*opstr; int32_t retval = -1;
sprintf(addr,"[\\\"ANY_SPROUT\\\"]");
//printf("z_sendmany from.(%s) -> %s\n",addr,destaddr);
if ( (retjson= get_komodocli(coinstr,&retstr,acname,"z_mergetoaddress",addr,destaddr,"","")) != 0 )
{
/*{
"remainingUTXOs": 0,
"remainingTransparentValue": 0.00000000,
"remainingNotes": 222,
"remainingShieldedValue": 5413.39093055,
"mergingUTXOs": 0,
"mergingTransparentValue": 0.00000000,
"mergingNotes": 10,
"mergingShieldedValue": 822.47447172,
"opid": "opid-f28f6261-4120-436c-aca5-859870a40a70"
}*/
if ( (opstr= jstr(retjson,"opid")) != 0 )
strcpy(opidstr,opstr);
retval = jint(retjson,"remainingNotes");

View File

@@ -269,7 +269,7 @@ int32_t dicefinish_utxosget(int32_t &total,struct dicefinish_utxo *utxos,int32_t
LOCK(mempool.cs);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
if ( myIsutxo_spentinmempool(it->first.txhash,(int32_t)it->first.index) == 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,it->first.txhash,(int32_t)it->first.index) == 0 )
{
if ( it->second.satoshis < threshold || it->second.satoshis > 10*threshold )
continue;
@@ -302,7 +302,7 @@ int32_t dice_betspent(char *debugstr,uint256 bettxid)
}
{
//LOCK(mempool.cs);
if ( myIsutxo_spentinmempool(bettxid,0) != 0 || myIsutxo_spentinmempool(bettxid,1) != 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,bettxid,0) != 0 || myIsutxo_spentinmempool(ignoretxid,ignorevin,bettxid,1) != 0 )
{
fprintf(stderr,"%s bettxid.%s already spent in mempool\n",debugstr,bettxid.GetHex().c_str());
return(-1);
@@ -1067,7 +1067,7 @@ uint64_t AddDiceInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubK
break;
if ( j != mtx.vin.size() )
continue;
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( myGetTransaction(txid,tx,hashBlock) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( (funcid= DecodeDiceOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid,hash,proof)) != 0 )
{
@@ -1176,7 +1176,7 @@ int64_t DicePlanFunds(uint64_t &entropyval,uint256 &entropytxid,uint64_t refsbit
continue;
}
}
if ( myIsutxo_spentinmempool(txid,vout) == 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
entropytxid = txid;
entropyval = tx.vout[0].nValue;
@@ -1451,7 +1451,7 @@ std::string DiceBet(uint64_t txfee,char *planstr,uint256 fundingtxid,int64_t bet
CCerror = "Your dealer is broke, find a new casino.";
return("");
}
if ( myIsutxo_spentinmempool(entropytxid,0) != 0 )
if ( myIsutxo_spentinmempool(ignoretxid,ignorevin,entropytxid,0) != 0 )
{
CCerror = "entropy txid is spent";
return("");

View File

@@ -85,6 +85,7 @@ bool Eval::Dispatch(const CC *cond, const CTransaction &txTo, unsigned int nIn)
CCinit(cp,ecode);
cp->didinit = 1;
}
switch ( ecode )
{
case EVAL_IMPORTPAYOUT:

View File

@@ -157,7 +157,7 @@ int64_t AddFaucetInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPub
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsFaucetvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= IsFaucetvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));

File diff suppressed because it is too large Load Diff

View File

@@ -255,11 +255,11 @@ template <class Helper> int64_t IsHeirFundingVout(struct CCcontract_info* cp, co
}
// makes coin initial tx opret
CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName)
CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo)
{
uint8_t evalcode = EVAL_HEIR;
return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName);
return CScript() << OP_RETURN << E_MARSHAL(ss << evalcode << funcid << ownerPubkey << heirPubkey << inactivityTimeSec << heirName << memo);
}
// makes coin additional tx opret
@@ -273,7 +273,7 @@ CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t hasHeirSpe
// decode opret vout for Heir contract
uint8_t _DecodeHeirOpRet(std::vector<uint8_t> vopret, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
uint8_t _DecodeHeirOpRet(std::vector<uint8_t> vopret, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
{
uint8_t evalCodeInOpret = 0;
uint8_t heirFuncId = 0;
@@ -287,13 +287,13 @@ uint8_t _DecodeHeirOpRet(std::vector<uint8_t> vopret, CPubKey& ownerPubkey, CPub
uint8_t heirFuncId = 0;
hasHeirSpendingBegun = 0;
bool result = E_UNMARSHAL(vopret, { ss >> evalCodeInOpret; ss >> heirFuncId; \
if (heirFuncId == 'F') { \
ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; \
} \
else { \
ss >> fundingTxidInOpret >> hasHeirSpendingBegun; \
} \
bool result = E_UNMARSHAL(vopret, { ss >> evalCodeInOpret; ss >> heirFuncId; \
if (heirFuncId == 'F') { \
ss >> ownerPubkey; ss >> heirPubkey; ss >> inactivityTime; ss >> heirName; ss >> memo; \
} \
else { \
ss >> fundingTxidInOpret >> hasHeirSpendingBegun; \
} \
});
if (!result) {
@@ -322,84 +322,50 @@ uint8_t _DecodeHeirOpRet(std::vector<uint8_t> vopret, CPubKey& ownerPubkey, CPub
return (uint8_t)0;
}
/* not used, see DecodeHeirOpRet(vopret,...)
// overload for 'F' opret
uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging)
{
uint256 dummytxid;
uint8_t dummyHasHeirSpendingBegun;
std::vector<uint8_t> vopret;
GetOpReturnData(scriptPubKey, vopret);
if (vopret.size() == 0) {
if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl;
return (uint8_t)0;
}
return _DecodeHeirOpRet(vopret, ownerPubkey, heirPubkey, inactivityTime, heirName, dummytxid, dummyHasHeirSpendingBegun, noLogging);
}*/
/* not used, see DecodeHeirOpRet(vopret,...)
// overload for A, C oprets and AddHeirContractInputs
uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
{
CPubKey dummyOwnerPubkey, dummyHeirPubkey;
int64_t dummyInactivityTime;
std::string dummyHeirName;
std::vector<uint8_t> vopret;
GetOpReturnData(scriptPubKey, vopret);
if (vopret.size() == 0) {
if (!noLogging) std::cerr << "DecodeHeirOpRet() warning: empty opret" << std::endl;
return (uint8_t)0;
}
return _DecodeHeirOpRet(vopret, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingtxidInOpret, hasHeirSpendingBegun, noLogging);
} */
// decode combined opret:
uint8_t _DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
uint8_t _DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint256& fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging)
{
uint8_t evalCodeTokens = 0;
std::vector<CPubKey> voutPubkeysDummy;
std::vector<uint8_t> vopretExtra, vopretStripped;
if (DecodeTokenOpRet(scriptPubKey, evalCodeTokens, tokenid, voutPubkeysDummy, vopretExtra) != 0) {
if (vopretExtra.size() > 1) {
uint8_t evalCodeTokens = 0;
std::vector<CPubKey> voutPubkeysDummy;
std::vector<uint8_t> vopretExtra /*, vopretStripped*/;
if (DecodeTokenOpRet(scriptPubKey, evalCodeTokens, tokenid, voutPubkeysDummy, vopretExtra) != 0) {
/* if (vopretExtra.size() > 1) {
// restore the second opret:
/* unmarshalled in DecodeTokenOpRet:
if (!E_UNMARSHAL(vopretExtra, { ss >> vopretStripped; })) { //strip string size
if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() could not unmarshal vopretStripped" << std::endl;
return (uint8_t)0;
}
}
else {
if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() empty vopretExtra" << std::endl;
return (uint8_t)0;
}
}
else
GetOpReturnData(scriptPubKey, vopretStripped);
return _DecodeHeirOpRet(vopretStripped, ownerPubkey, heirPubkey, inactivityTime, heirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging);
} */
if (vopretExtra.size() < 1) {
if (!noLogging) std::cerr << "_DecodeHeirEitherOpret() empty vopretExtra" << std::endl;
return (uint8_t)0;
}
}
else {
GetOpReturnData(scriptPubKey, vopretExtra);
}
return _DecodeHeirOpRet(vopretExtra, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, fundingTxidInOpret, hasHeirSpendingBegun, noLogging);
}
// overload to decode opret in fundingtxid:
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging) {
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, bool noLogging) {
uint256 dummyFundingTxidInOpret;
uint8_t dummyHasHeirSpendingBegun;
return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, dummyFundingTxidInOpret, dummyHasHeirSpendingBegun, noLogging);
return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, dummyFundingTxidInOpret, dummyHasHeirSpendingBegun, noLogging);
}
// overload to decode opret in A and C heir tx:
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging) {
CPubKey dummyOwnerPubkey, dummyHeirPubkey;
int64_t dummyInactivityTime;
std::string dummyHeirName;
std::string dummyHeirName, dummyMemo;
return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, fundingTxidInOpret, hasHeirSpendingBegun, noLogging);
return _DecodeHeirEitherOpRet(scriptPubKey, tokenid, dummyOwnerPubkey, dummyHeirPubkey, dummyInactivityTime, dummyHeirName, dummyMemo, fundingTxidInOpret, hasHeirSpendingBegun, noLogging);
}
// check if pubkey is in vins
@@ -423,7 +389,7 @@ void CheckVinPubkey(std::vector<CTxIn> vins, CPubKey pubkey, bool &hasPubkey, bo
* find the latest funding tx: it may be the first F tx or one of A or C tx's
* Note: this function is also called from validation code (use non-locking calls)
*/
uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, CScript& fundingOpretScript, uint8_t &hasHeirSpendingBegun)
uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, CScript& fundingOpretScript, uint8_t &hasHeirSpendingBegun)
{
CTransaction fundingtx;
uint256 hashBlock;
@@ -440,7 +406,7 @@ uint256 _FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &toke
if (myGetTransaction(fundingtxid, fundingtx, hashBlock) && fundingtx.vout.size()) {
CScript heirScript = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript();
uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
uint8_t funcId = DecodeHeirEitherOpRet(heirScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
if (funcId != 0) {
// found at least funding tx!
//std::cerr << "FindLatestFundingTx() lasttx currently is fundingtx, txid=" << fundingtxid.GetHex() << " opreturn type=" << (char)funcId << '\n';
@@ -522,17 +488,17 @@ uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRe
CPubKey ownerPubkey;
CPubKey heirPubkey;
int64_t inactivityTime;
std::string heirName;
std::string heirName, memo;
return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun);
return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, opRetScript, hasHeirSpendingBegun);
}
// overload for transaction creation code
uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, uint8_t &hasHeirSpendingBegun)
uint256 FindLatestFundingTx(uint256 fundingtxid, uint8_t& funcId, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, uint8_t &hasHeirSpendingBegun)
{
CScript opRetScript;
return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, opRetScript, hasHeirSpendingBegun);
return _FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, opRetScript, hasHeirSpendingBegun);
}
// add inputs of 1 of 2 cc address
@@ -561,7 +527,7 @@ template <class Helper> int64_t Add1of2AddressInputs(struct CCcontract_info* cp,
// no need to prevent dup
// dimxy: maybe it is good to put tx's in cache?
std::cerr << "Add1of2AddressInputs() txid=" << txid.GetHex() << std::endl;
//std::cerr << "Add1of2AddressInputs() txid=" << txid.GetHex() << std::endl;
if (GetTransaction(txid, heirtx, hashBlock, false) != 0) {
uint256 tokenid;
@@ -576,7 +542,7 @@ template <class Helper> int64_t Add1of2AddressInputs(struct CCcontract_info* cp,
isMyFuncId(funcId) &&
(typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, voutIndex, tokenid) > 0) && // token validation logic
//(voutValue = IsHeirFundingVout<Helper>(cp, heirtx, voutIndex, ownerPubkey, heirPubkey)) > 0 && // heir contract vout validation logic - not used since we moved to 2-eval vouts
!myIsutxo_spentinmempool(txid, voutIndex))
!myIsutxo_spentinmempool(ignoretxid,ignorevin,txid, voutIndex))
{
std::cerr << "Add1of2AddressInputs() satoshis=" << it->second.satoshis << std::endl;
if (total != 0 && maxinputs != 0)
@@ -626,7 +592,7 @@ template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info
(txid == fundingtxid || fundingTxidInOpret == fundingtxid) &&
isMyFuncId(funcId) && !isSpendingTx(funcId) &&
(typeid(Helper) != typeid(TokenHelper) || IsTokensvout(true, true, cp, nullptr, heirtx, ivout, tokenid) > 0) &&
!myIsutxo_spentinmempool(txid, ivout)) // exclude tx in mempool
!myIsutxo_spentinmempool(ignoretxid,ignorevin,txid, ivout)) // exclude tx in mempool
{
total += it->second; // dont do this: tx.vout[ivout].nValue; // in vin[0] always is the pay to 1of2 addr (funding or change)
//std::cerr << "LifetimeHeirContractFunds() added tx=" << txid.GetHex() << " it->second=" << it->second << " vout[0].nValue=" << tx.vout[ivout].nValue << " opreturn=" << (char)funcId << '\n';
@@ -644,7 +610,7 @@ template <class Helper> int64_t LifetimeHeirContractFunds(struct CCcontract_info
* and also for setting spending plan for the funds' owner and heir
* @return fundingtxid handle for subsequent references to this heir funding plan
*/
template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid)
template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid)
{
UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -657,13 +623,7 @@ template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std
int64_t markerfee = 10000;
//std::cerr << "HeirFund() amount=" << amount << " txfee=" << txfee << " heirPubkey IsValid()=" << heirPubkey.IsValid() << " inactivityTime(sec)=" << inactivityTimeSec << " tokenid=" << tokenid.GetHex() << std::endl;
if (!heirPubkey.IsValid()) {
std::cerr << "HeirFund() heirPubkey is not valid!" << std::endl;
result.push_back(Pair("result", "error"));
result.push_back(Pair("error", "invalid heir pubkey"));
}
CPubKey myPubkey = pubkey2pk(Mypubkey());
if (AddNormalinputs(mtx, myPubkey, markerfee, 3) > 0) {
@@ -711,10 +671,10 @@ template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std
// add change for txfee and opreturn vouts and sign tx:
std::string rawhextx = FinalizeCCTx(0, cp, mtx, myPubkey, txfee,
Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName));
Helper::makeCreateOpRet(tokenid, voutTokenPubkeys, myPubkey, heirPubkey, inactivityTimeSec, heirName, memo));
if (!rawhextx.empty()) {
result.push_back(Pair("result", "success"));
result.push_back(Pair("hextx", rawhextx));
result.push_back(Pair("hex", rawhextx));
}
else {
std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl;
@@ -737,12 +697,12 @@ template <typename Helper> UniValue _HeirFund(int64_t txfee, int64_t amount, std
}
// if no these callers - it could not link
UniValue HeirFundCoinCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid){
return _HeirFund<CoinHelper>(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, tokenid);
UniValue HeirFundCoinCaller(int64_t txfee, int64_t coins, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo){
return _HeirFund<CoinHelper>(txfee, coins, heirName, heirPubkey, inactivityTimeSec, memo, zeroid);
}
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, uint256 tokenid) {
return _HeirFund<TokenHelper>(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, tokenid);
UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirName, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string memo, uint256 tokenid) {
return _HeirFund<TokenHelper>(txfee, satoshis, heirName, heirPubkey, inactivityTimeSec, memo, tokenid);
}
/**
@@ -750,7 +710,7 @@ UniValue HeirFundTokenCaller(int64_t txfee, int64_t satoshis, std::string heirNa
* creates tx to add more funds to cryptocondition address for spending by either funds' owner or heir
* @return result object with raw tx or error text
*/
template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun)
template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint8_t hasHeirSpendingBegun)
{
UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -835,7 +795,7 @@ template <class Helper> UniValue _HeirAdd(uint256 fundingtxid, int64_t txfee, in
Helper::makeAddOpRet(tokenid, voutTokenPubkeys, fundingtxid, hasHeirSpendingBegun)));
if (!rawhextx.empty()) {
result.push_back(Pair("hextx", rawhextx));
result.push_back(Pair("hex", rawhextx));
}
else {
std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl;
@@ -868,10 +828,10 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount
uint256 latesttxid, tokenid = zeroid;
uint8_t funcId;
std::string heirName;
std::string heirName, memo;
uint8_t hasHeirSpendingBegun = 0;
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) {
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun)) != zeroid) {
if (tokenid == zeroid) {
int64_t amount = (int64_t)(atof(strAmount.c_str()) * COIN);
if (amount <= 0) {
@@ -880,8 +840,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirAdd<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
return _HeirAdd<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun);
}
else {
int64_t amount = atoll(strAmount.c_str());
@@ -891,7 +850,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirAdd<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
return _HeirAdd<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun);
}
}
else {
@@ -910,7 +869,7 @@ UniValue HeirAddCaller(uint256 fundingtxid, int64_t txfee, std::string strAmount
* creates tx to spend funds from cryptocondition address by either funds' owner or heir
* @return result object with raw tx or error text
*/
template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, uint8_t hasHeirSpendingBegun)
template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee, int64_t amount, uint256 latesttxid, uint8_t funcId, uint256 tokenid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, uint8_t hasHeirSpendingBegun)
{
UniValue result(UniValue::VOBJ);
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
@@ -1008,7 +967,7 @@ template <typename Helper>UniValue _HeirClaim(uint256 fundingtxid, int64_t txfee
if (!rawhextx.empty()) {
result.push_back(Pair("result", "success"));
result.push_back(Pair("hextx", rawhextx));
result.push_back(Pair("hex", rawhextx));
}
else {
std::cerr << "HeirAdd error in FinalizeCCtx" << std::endl;
@@ -1038,10 +997,10 @@ UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmou
uint256 latesttxid, tokenid = zeroid;
uint8_t funcId;
std::string heirName;
std::string heirName, memo;
uint8_t hasHeirSpendingBegun = 0;
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun)) != zeroid) {
if ((latesttxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun)) != zeroid) {
if (tokenid == zeroid) {
int64_t amount = (int64_t)(atof(strAmount.c_str()) * COIN);
if (amount < 0) {
@@ -1050,7 +1009,7 @@ UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmou
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirClaim<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
return _HeirClaim<CoinHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun);
}
else {
int64_t amount = atoll(strAmount.c_str());
@@ -1060,7 +1019,7 @@ UniValue HeirClaimCaller(uint256 fundingtxid, int64_t txfee, std::string strAmou
result.push_back(Pair("error", "invalid amount"));
return result;
}
return _HeirClaim<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
return _HeirClaim<TokenHelper>(fundingtxid, txfee, amount, latesttxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, hasHeirSpendingBegun);
}
}
@@ -1099,7 +1058,7 @@ UniValue HeirInfo(uint256 fundingtxid)
CPubKey ownerPubkey, heirPubkey;
uint256 dummyTokenid, tokenid = zeroid; // important to clear tokenid
std::string heirName;
std::string heirName, memo;
int64_t inactivityTimeSec;
const bool noLogging = false;
uint8_t funcId;
@@ -1118,7 +1077,7 @@ UniValue HeirInfo(uint256 fundingtxid)
uint8_t hasHeirSpendingBegun = 0;
uint256 latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, hasHeirSpendingBegun);
uint256 latestFundingTxid = FindLatestFundingTx(fundingtxid, funcId, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, hasHeirSpendingBegun);
if (latestFundingTxid != zeroid) {
int32_t numblocks;
@@ -1159,12 +1118,22 @@ UniValue HeirInfo(uint256 fundingtxid)
else
total = LifetimeHeirContractFunds<TokenHelper>(cp, fundingtxid, ownerPubkey, heirPubkey);
msg = "type";
if (tokenid == zeroid) {
stream << "coins";
}
else {
stream << "tokens";
}
result.push_back(Pair(msg, stream.str().c_str()));
stream.str("");
stream.clear();
msg = "lifetime";
if (tokenid == zeroid) {
msg = "funding total in coins";
stream << std::fixed << std::setprecision(8) << (double)total / COIN;
}
else {
msg = "funding total in tokens";
stream << total;
}
result.push_back(Pair(msg, stream.str().c_str()));
@@ -1177,12 +1146,11 @@ UniValue HeirInfo(uint256 fundingtxid)
else
inputs = Add1of2AddressInputs<TokenHelper>(cp, fundingtxid, mtx, ownerPubkey, heirPubkey, 0, 60);
msg = "available";
if (tokenid == zeroid) {
msg = "funding available in coins";
stream << std::fixed << std::setprecision(8) << (double)inputs / COIN;
}
else {
msg = "funding available in tokens";
stream << inputs;
}
result.push_back(Pair(msg, stream.str().c_str()));
@@ -1192,14 +1160,14 @@ UniValue HeirInfo(uint256 fundingtxid)
if (tokenid != zeroid) {
int64_t ownerInputs = TokenHelper::addOwnerInputs(tokenid, mtx, ownerPubkey, 0, (int32_t)64);
stream << ownerInputs;
msg = "owner funding available in tokens";
msg = "OwnerRemainderTokens";
result.push_back(Pair(msg, stream.str().c_str()));
stream.str("");
stream.clear();
}
stream << inactivityTimeSec;
result.push_back(Pair("inactivity time setting, sec", stream.str().c_str()));
result.push_back(Pair("InactivityTimeSetting", stream.str().c_str()));
stream.str("");
stream.clear();
@@ -1209,18 +1177,20 @@ UniValue HeirInfo(uint256 fundingtxid)
}
stream << std::boolalpha << (hasHeirSpendingBegun || durationSec > inactivityTimeSec);
result.push_back(Pair("spending allowed for the heir", stream.str().c_str()));
result.push_back(Pair("IsHeirSpendingAllowed", stream.str().c_str()));
stream.str("");
stream.clear();
// adding owner current inactivity time:
if (!hasHeirSpendingBegun && durationSec <= inactivityTimeSec) {
stream << durationSec;
result.push_back(Pair("owner inactivity time, sec", stream.str().c_str()));
result.push_back(Pair("InactivityTime", stream.str().c_str()));
stream.str("");
stream.clear();
}
result.push_back(Pair("memo", memo.c_str()));
result.push_back(Pair("result", "success"));
}
else {
@@ -1262,18 +1232,18 @@ void _HeirList(struct CCcontract_info *cp, UniValue &result)
CTransaction fundingtx;
if (GetTransaction(txid, fundingtx, hashBlock, false)) {
CPubKey ownerPubkey, heirPubkey;
std::string heirName;
std::string heirName, memo;
int64_t inactivityTimeSec;
const bool noLogging = true;
uint256 tokenid;
CScript opret = (fundingtx.vout.size() > 0) ? fundingtx.vout[fundingtx.vout.size() - 1].scriptPubKey : CScript();
uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, true);
uint8_t funcId = DecodeHeirEitherOpRet(opret, tokenid, ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo, true);
// note: if it is not Heir token funcId would be equal to 0
if (funcId == 'F') {
//result.push_back(Pair("fundingtxid kind name", txid.GetHex() + std::string(" ") + (typeid(Helper) == typeid(TokenHelper) ? std::string("token") : std::string("coin")) + std::string(" ") + heirName));
result.push_back( Pair("fundingtxid", txid.GetHex()) );
result.push_back( txid.GetHex() );
}
else {
std::cerr << "HeirList() this is not the initial F transaction=" << txid.GetHex() << std::endl;
@@ -1288,17 +1258,14 @@ void _HeirList(struct CCcontract_info *cp, UniValue &result)
UniValue HeirList()
{
UniValue result(UniValue::VOBJ);
result.push_back(Pair("result", "success"));
UniValue result(UniValue::VARR);
//result.push_back(Pair("result", "success"));
//result.push_back(Pair("name", "Heir List"));
struct CCcontract_info *cpHeir, *cpTokens, heirC, tokenC; // NOTE we must use a separate 'C' structure for each CCinit!
struct CCcontract_info *cpHeir, heirC;
cpHeir = CCinit(&heirC, EVAL_HEIR);
//cpTokens = CCinit(&tokenC, EVAL_TOKENS);
_HeirList(cpHeir, result);
//_HeirList<TokenHelper>(cpTokens, result); not used anymore
return result;
}

View File

@@ -7,13 +7,13 @@
#define IS_CHARINSTR(c, str) (std::string(str).find((char)(c)) != std::string::npos)
// makes coin initial tx opret
CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName);
CScript EncodeHeirCreateOpRet(uint8_t funcid, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo);
CScript EncodeHeirOpRet(uint8_t funcid, uint256 fundingtxid, uint8_t isHeirSpendingBegan);
uint256 FindLatestFundingTx(uint256 fundingtxid, uint256 &tokenid, CScript& opRetScript, uint8_t &isHeirSpendingBegan);
//uint8_t DecodeHeirOpRet(CScript scriptPubKey, uint256& fundingtxid, uint8_t &isHeirSpendingBegan, bool noLogging = false);
//uint8_t DecodeHeirOpRet(CScript scriptPubKey, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false);
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, bool noLogging = false);
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, CPubKey& ownerPubkey, CPubKey& heirPubkey, int64_t& inactivityTime, std::string& heirName, std::string& memo, bool noLogging = false);
uint8_t DecodeHeirEitherOpRet(CScript scriptPubKey, uint256 &tokenid, uint256 &fundingTxidInOpret, uint8_t &hasHeirSpendingBegun, bool noLogging = false);
inline static bool isMyFuncId(uint8_t funcid) { return IS_CHARINSTR(funcid, "FAC"); }
@@ -28,8 +28,8 @@ public:
return AddNormalinputs(mtx, ownerPubkey, total, maxinputs);
}
static CScript makeCreateOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) {
return EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName);
static CScript makeCreateOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) {
return EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo);
}
static CScript makeAddOpRet(uint256 dummyid, std::vector<CPubKey> dummyPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
return EncodeHeirOpRet((uint8_t)'A', fundingtxid, isHeirSpendingBegan);
@@ -51,8 +51,11 @@ public:
cpHeir = CCinit(&heirC, EVAL_HEIR);
return GetCCaddress1of2(cpHeir, coinaddr, ownerPubkey, heirPubkey);
}
static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr) {
CCaddr1of2set(cp, ownerPubkey, heirPubkey, coinaddr);
static void CCaddrCoinsOrTokens1of2set(struct CCcontract_info *cp, CPubKey ownerPubkey, CPubKey heirPubkey, char *coinaddr)
{
uint8_t mypriv[32];
Myprivkey(mypriv);
CCaddr1of2set(cp, ownerPubkey, heirPubkey,mypriv, coinaddr);
}
};
@@ -66,9 +69,9 @@ public:
return AddTokenCCInputs(cpHeir, mtx, ownerPubkey, tokenid, total, maxinputs);
}
static CScript makeCreateOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName) {
static CScript makeCreateOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, CPubKey ownerPubkey, CPubKey heirPubkey, int64_t inactivityTimeSec, std::string heirName, std::string memo) {
return EncodeTokenOpRet(tokenid, voutTokenPubkeys,
EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName));
EncodeHeirCreateOpRet((uint8_t)'F', ownerPubkey, heirPubkey, inactivityTimeSec, heirName, memo));
}
static CScript makeAddOpRet(uint256 tokenid, std::vector<CPubKey> voutTokenPubkeys, uint256 fundingtxid, uint8_t isHeirSpendingBegan) {
return EncodeTokenOpRet(tokenid, voutTokenPubkeys,
@@ -407,10 +410,10 @@ public:
//std::cerr << "CCC1of2AddressValidator::validateVout() entered" << std::endl;
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTime;
std::string heirName;
std::string heirName, memo;
uint256 tokenid;
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
if (funcId == 0) {
message = m_customMessage + std::string(" invalid opreturn format");
std::cerr << "CCC1of2AddressValidator::validateVout() exits with false: " << message << std::endl;
@@ -462,13 +465,13 @@ public:
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTime;
std::string heirName;
std::string heirName, memo;
uint256 tokenid;
///std::cerr << "CMyPubkeyVoutValidator::validateVout() m_opRetScript=" << m_opRetScript.ToString() << std::endl;
// get both pubkeys:
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
if (funcId == 0) {
message = std::string("invalid opreturn format");
return false;
@@ -522,11 +525,11 @@ public:
CPubKey ownerPubkey, heirPubkey;
int64_t inactivityTime;
std::string heirName;
std::string heirName, memo;
uint256 tokenid;
// get heir pubkey:
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, true);
uint8_t funcId = DecodeHeirEitherOpRet(m_fundingOpretScript, tokenid, ownerPubkey, heirPubkey, inactivityTime, heirName, memo, true);
if (funcId == 0) {
message = std::string("invalid opreturn format");
return false;

View File

@@ -20,6 +20,10 @@
#include "primitives/transaction.h"
#include "cc/CCinclude.h"
//#define LEV_INFO 0
//#define LEV_DEBUG1 1
//#define LOGSTREAM(category, level, logoperator) { std::ostringstream stream; logoperator; for(int i = 0; i < level; i ++) if( LogAcceptCategory( (std::string(category) + (level > 0 ? std::string("-")+std::to_string(level) : std::string("") )).c_str() ) ) LogPrintStr(stream.str()); }
/*
* CC Eval method for import coin.
*
@@ -33,63 +37,299 @@ extern std::string ASSETCHAINS_SELFIMPORT;
extern uint16_t ASSETCHAINS_CODAPORT,ASSETCHAINS_BEAMPORT;
extern uint8_t ASSETCHAINS_OVERRIDE_PUBKEY33[33];
int32_t GetSelfimportProof(std::string source,CMutableTransaction &mtx,CScript &scriptPubKey,TxProof &proof,uint64_t burnAmount,std::vector<uint8_t> rawtx,uint256 txid,std::vector<uint8_t> rawproof) // find burnTx with hash from "other" daemon
// utilities from gateways.cpp
uint256 BitcoinGetProofMerkleRoot(const std::vector<uint8_t> &proofData, std::vector<uint256> &txids);
uint256 GatewaysReverseScan(uint256 &txid, int32_t height, uint256 reforacletxid, uint256 batontxid);
int32_t GatewaysCointxidExists(struct CCcontract_info *cp, uint256 cointxid);
uint8_t DecodeGatewaysBindOpRet(char *depositaddr, const CScript &scriptPubKey, std::string &coin, uint256 &tokenid, int64_t &totalsupply, uint256 &oracletxid, uint8_t &M, uint8_t &N, std::vector<CPubKey> &pubkeys, uint8_t &taddr, uint8_t &prefix, uint8_t &prefix2);
// ac_import=chain support:
// encode opret for gateways import
CScript EncodeGatewaysImportTxOpRet(uint32_t targetCCid, std::string coin, uint256 bindtxid, std::vector<CPubKey> publishers, std::vector<uint256>txids, int32_t height, uint256 cointxid, int32_t claimvout, std::string rawburntx, std::vector<uint8_t>proof, CPubKey destpub, int64_t amount)
{
MerkleBranch newBranch; CMutableTransaction tmpmtx; CTransaction tx,vintx; uint256 blockHash; char destaddr[64],pkaddr[64];
tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(),komodo_nextheight());
if ( source == "BEAM" )
CScript opret;
opret << OP_RETURN << E_MARSHAL(ss << targetCCid << coin << bindtxid << publishers << txids << height << cointxid << claimvout << rawburntx << proof << destpub << amount);
return(opret);
}
bool ImportCoinGatewaysVerify(char *refdepositaddr, uint256 oracletxid, int32_t claimvout, std::string refcoin, uint256 burntxid, const std::string rawburntx, std::vector<uint8_t>proof, uint256 merkleroot)
{
std::vector<uint256> txids;
uint256 proofroot, hashBlock, foundtxid = zeroid;
CTransaction oracletx, burntx;
std::string name, description, format;
char destaddr[64], destpubaddr[64], claimaddr[64];
int32_t i, numvouts;
int64_t nValue = 0;
if (myGetTransaction(oracletxid, oracletx, hashBlock) == 0 || (numvouts = oracletx.vout.size()) <= 0)
{
if ( ASSETCHAINS_BEAMPORT == 0 )
return(-1);
// confirm via ASSETCHAINS_BEAMPORT that burnTx/hash is a valid BEAM burn
// return(0);
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify can't find oracletxid=" << oracletxid.GetHex() << std::endl);
return false;
}
else if ( source == "CODA" )
if (DecodeOraclesCreateOpRet(oracletx.vout[numvouts - 1].scriptPubKey, name, description, format) != 'C' || name != refcoin)
{
if ( ASSETCHAINS_CODAPORT == 0 )
return(-1);
// confirm via ASSETCHAINS_CODAPORT that burnTx/hash is a valid CODA burn
// return(0);
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched oracle name=" << name.c_str() << " != " << refcoin.c_str() << std::endl);
return false;
}
else
proofroot = BitcoinGetProofMerkleRoot(proof, txids);
if (proofroot != merkleroot)
{
if ( !E_UNMARSHAL(rawtx, ss >> tx) )
return(-1);
scriptPubKey = tx.vout[0].scriptPubKey;
mtx = tx;
mtx.fOverwintered = tmpmtx.fOverwintered;
mtx.nExpiryHeight = tmpmtx.nExpiryHeight;
mtx.nVersionGroupId = tmpmtx.nVersionGroupId;
mtx.nVersion = tmpmtx.nVersion;
mtx.vout.clear();
mtx.vout.resize(1);
mtx.vout[0].nValue = burnAmount;
mtx.vout[0].scriptPubKey = scriptPubKey;
if ( tx.GetHash() != txid )
return(-1);
if ( source == "PUBKEY" )
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify mismatched proof merkleroot=" << proofroot.GetHex() << " and oracles merkleroot=" << merkleroot.GetHex() << std::endl);
return false;
}
// check the burntxid is in the proof:
if (std::find(txids.begin(), txids.end(), burntxid) == txids.end()) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "ImportCoinGatewaysVerify invalid proof for this burntxid=" << burntxid.GetHex() << std::endl);
return false;
}
/*
if (DecodeHexTx(burntx, rawburntx) != 0)
{
Getscriptaddress(claimaddr, burntx.vout[claimvout].scriptPubKey);
Getscriptaddress(destpubaddr, CScript() << ParseHex(HexStr(destpub)) << OP_CHECKSIG);
if (strcmp(claimaddr, destpubaddr) == 0)
{
// make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33
if ( myGetTransaction(tx.vin[0].prevout.hash,vintx,blockHash) == 0 )
return(-1);
if ( tx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr,vintx.vout[tx.vin[0].prevout.n].scriptPubKey) != 0 )
for (i = 0; i<numvouts; i++)
{
pubkey2addr(pkaddr,ASSETCHAINS_OVERRIDE_PUBKEY33);
if ( strcmp(pkaddr,destaddr) == 0 )
Getscriptaddress(destaddr, burntx.vout[i].scriptPubKey);
if (strcmp(refdepositaddr, destaddr) == 0)
{
proof = std::make_pair(txid,newBranch);
return(0);
foundtxid = burntx.GetHash();
nValue = burntx.vout[i].nValue;
break;
}
fprintf(stderr,"mismatched vin0[%d] -> %s vs %s\n",tx.vin[0].prevout.n,destaddr,pkaddr);
}
}
else if ( source == ASSETCHAINS_SELFIMPORT )
else fprintf(stderr, "claimaddr.(%s) != destpubaddr.(%s)\n", claimaddr, destpubaddr);
}*/
/*
if (foundtxid == burntxid) {
LOGSTREAM("importcoin", LEV_DEBUG1, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in merkleroot merkleroot" << std::endl);
return(nValue);
}
else {
LOGSTREAM("importcoin", LEV_INFO, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in merkleroot merkleroot" << std::endl);
fprintf(stderr, "(%s) != (%s) or txid %s mismatch.%d or script mismatch\n", refdepositaddr, destaddr, uint256_str(str, foundtxid), foundtxid != burntxid);
*/
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "verified proof for burntxid=" << burntxid.GetHex() << " in trusted merkleroot" << std::endl);
return true;
}
// make import tx with burntx and its proof of existence
std::string MakeGatewaysImportTx(uint64_t txfee, uint256 bindtxid, int32_t height, std::string refcoin, std::vector<uint8_t>proof, std::string rawburntx, int32_t ivout, uint256 burntxid)
{
CMutableTransaction mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
CTransaction burntx, bindtx;
CPubKey mypk, gatewayspk;
uint256 oracletxid, merkleroot, mhash, hashBlock, tokenid, txid;
int64_t totalsupply;
int32_t i, m, n, numvouts;
uint8_t M, N, taddr, prefix, prefix2;
std::string coin;
struct CCcontract_info *cp, C;
std::vector<CPubKey> pubkeys, publishers;
std::vector<uint256>txids;
char depositaddr[64], txidaddr[64];
cp = CCinit(&C, EVAL_GATEWAYS);
/*if (txfee == 0)
txfee = 10000;
mypk = pubkey2pk(Mypubkey());
gatewayspk = GetUnspendable(cp, 0); */
if (!E_UNMARSHAL(ParseHex(rawburntx), ss >> burntx))
return std::string("");
CAmount amount = GetCoinImportValue(burntx); // equal to int64_t
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx height=" << height << " coin=" << refcoin << " amount=" << (double)amount / COIN << " pubkeys num=" << pubkeys.size() << std::endl);
if (GetTransaction(bindtxid, bindtx, hashBlock, false) == 0 || (numvouts = bindtx.vout.size()) <= 0)
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx cant find bindtxid=" << bindtxid.GetHex() << std::endl);
return("");
}
/* if (DecodeGatewaysBindOpRet(depositaddr, bindtx.vout[numvouts - 1].scriptPubKey, coin, tokenid, totalsupply, oracletxid, M, N, pubkeys, taddr, prefix, prefix2) != 'B' || refcoin != coin)
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx invalid coin - bindtxid=" << bindtxid.GetHex() << " coin=" << coin.c_str() << std::endl);
return("");
} eliminate link err */
n = (int32_t)pubkeys.size();
merkleroot = zeroid;
for (i = m = 0; i < n; i++)
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx using pubkeys[" << i << "]=" << HexStr(pubkeys[i]) << std::endl);
if ((mhash = GatewaysReverseScan(txid, height, oracletxid, OraclesBatontxid(oracletxid, pubkeys[i]))) != zeroid)
{
// source is external coin is the assetchains symbol in the burnTx OP_RETURN
// burnAmount, rawtx and rawproof should be enough for gatewaysdeposit equivalent
if (merkleroot == zeroid)
merkleroot = mhash, m = 1;
else if (mhash == merkleroot)
m ++;
publishers.push_back(pubkeys[i]);
txids.push_back(txid);
}
}
return(-1);
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " nodes m=" << m << " of n=" << n << std::endl);
if (merkleroot == zeroid || m < n / 2) // none or less than half oracle nodes sent merkleroot
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx couldnt find merkleroot for block height=" << height << "coin=" << coin.c_str() << " oracleid=" << oracletxid.GetHex() << " m=" << m << " vs n=" << n << std::endl );
return("");
}
if (GatewaysCointxidExists(cp, burntxid) != 0)
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx burntxid=" << burntxid.GetHex() << " already exists" << std::endl);
return("");
}
if (!ImportCoinGatewaysVerify(depositaddr, oracletxid, ivout, coin, burntxid, rawburntx, proof, merkleroot))
{
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeGatewaysImportTx could not validate burntx, txid=" << burntxid.GetHex() << std::endl);
return("");
}
std::vector<uint256> leaftxids;
BitcoinGetProofMerkleRoot(proof, leaftxids);
MerkleBranch newBranch(0, leaftxids);
TxProof txProof = std::make_pair(burntxid, newBranch);
std::vector<CTxOut> vouts;
return HexStr(E_MARSHAL(ss << MakeImportCoinTransaction(txProof, burntx, vouts)));
/*if (AddNormalinputs(mtx, mypk, 3 * txfee, 4) > 0)
{
mtx.vout.push_back(MakeCC1vout(cp->evalcode, txfee, destpub));
mtx.vout.push_back(CTxOut(txfee, CScript() << ParseHex(HexStr(CCtxidaddr(txidaddr, burntxid))) << OP_CHECKSIG));
return(FinalizeCCTx(0, cp, mtx, mypk, txfee, EncodeGatewaysImportTxOpRet(0xFFFFFFFF, coin, bindtxid, publishers, txids, height, burntxid, ivout, rawburntx, proof, destpub, amount)));
}
LOGSTREAM("importcoin", LEV_INFO, stream << "MakeGatewaysImportTx coud not find normal imputs" << std::endl);*/
return("");
}
// makes source tx for self import tx
std::string MakeSelfImportSourceTx(CTxDestination &dest, int64_t amount, CMutableTransaction &mtx)
{
const int64_t txfee = 10000;
int64_t inputs, change;
CPubKey myPubKey = Mypubkey();
struct CCcontract_info *cpDummy, C;
cpDummy = CCinit(&C, EVAL_TOKENS);
mtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
if( (inputs = AddNormalinputs(mtx, myPubKey, txfee, 4)) == 0 ) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "MakeSelfImportSourceTx: cannot find normal imputs for txfee" << std::endl);
return std::string("");
}
CScript scriptPubKey = GetScriptForDestination(dest);
mtx.vout.push_back(CTxOut(txfee, scriptPubKey));
change = inputs - txfee;
if( change != 0 )
mtx.vout.push_back(CTxOut(change, CScript() << ParseHex(HexStr(myPubKey)) << OP_CHECKSIG));
//make opret with amount:
return FinalizeCCTx(0, cpDummy, mtx, myPubKey, txfee, CScript() << OP_RETURN << E_MARSHAL(ss << (uint8_t)EVAL_IMPORTCOIN << (uint8_t)'A' << amount));
}
// make sure vin0 is signed by ASSETCHAINS_OVERRIDE_PUBKEY33
int32_t CheckVin0PubKey(const CTransaction &sourcetx)
{
CTransaction vintx;
uint256 blockHash;
char destaddr[64], pkaddr[64];
if( !myGetTransaction(sourcetx.vin[0].prevout.hash, vintx, blockHash) ) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() could not load vintx" << sourcetx.vin[0].prevout.hash.GetHex() << std::endl);
return(-1);
}
if( sourcetx.vin[0].prevout.n < vintx.vout.size() && Getscriptaddress(destaddr, vintx.vout[sourcetx.vin[0].prevout.n].scriptPubKey) != 0 )
{
pubkey2addr(pkaddr, ASSETCHAINS_OVERRIDE_PUBKEY33);
if (strcmp(pkaddr, destaddr) == 0) {
return(0);
}
LOGSTREAM("importcoin", CCLOG_INFO, stream << "CheckVin0PubKey() mismatched vin0[prevout.n=" << sourcetx.vin[0].prevout.n << "] -> destaddr=" << destaddr << " vs pkaddr=" << pkaddr << std::endl);
}
return -1;
}
// ac_import=PUBKEY support:
// prepare a tx for creating import tx and quasi-burn tx
int32_t GetSelfimportProof(std::string source, CMutableTransaction &mtx, CScript &scriptPubKey, TxProof &proof, std::string rawsourcetx, int32_t &ivout, uint256 sourcetxid, uint64_t burnAmount) // find burnTx with hash from "other" daemon
{
MerkleBranch newBranch;
CMutableTransaction tmpmtx;
CTransaction sourcetx;
tmpmtx = CreateNewContextualCMutableTransaction(Params().GetConsensus(), komodo_nextheight());
if (!E_UNMARSHAL(ParseHex(rawsourcetx), ss >> sourcetx)) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: could not unmarshal source tx" << std::endl);
return(-1);
}
if (sourcetx.vout.size() == 0) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: vout size is 0" << std::endl);
return -1;
}
if (ivout < 0) { // "ivout < 0" means "find"
// try to find vout
CPubKey myPubkey = Mypubkey();
ivout = 0;
// skip change:
if (sourcetx.vout[ivout].scriptPubKey == (CScript() << ParseHex(HexStr(myPubkey)) << OP_CHECKSIG))
ivout++;
}
if (ivout >= sourcetx.vout.size()) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: needed vout not found" << std::endl);
return -1;
}
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "GetSelfimportProof: using vout[" << ivout << "] of the passed rawtx" << std::endl);
scriptPubKey = sourcetx.vout[ivout].scriptPubKey;
//mtx is template for import tx
mtx = sourcetx;
mtx.fOverwintered = tmpmtx.fOverwintered;
//malleability fix for burn tx:
//mtx.nExpiryHeight = tmpmtx.nExpiryHeight;
mtx.nExpiryHeight = sourcetx.nExpiryHeight;
mtx.nVersionGroupId = tmpmtx.nVersionGroupId;
mtx.nVersion = tmpmtx.nVersion;
mtx.vout.clear();
mtx.vout.resize(1);
mtx.vout[0].nValue = burnAmount;
mtx.vout[0].scriptPubKey = scriptPubKey;
// not sure we need this now as we create sourcetx ourselves:
if (sourcetx.GetHash() != sourcetxid) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "GetSelfimportProof: passed source txid incorrect" << std::endl);
return(-1);
}
// check ac_pubkey:
if (CheckVin0PubKey(sourcetx) < 0) {
return -1;
}
proof = std::make_pair(sourcetxid, newBranch);
return 0;
}
// use proof from the above functions to validate the import
@@ -116,9 +356,52 @@ int32_t CheckGATEWAYimport(TxProof proof,std::vector<uint8_t> rawproof,CTransact
int32_t CheckPUBKEYimport(TxProof proof,std::vector<uint8_t> rawproof,CTransaction burnTx,std::vector<CTxOut> payouts)
{
// if burnTx has ASSETCHAINS_PUBKEY vin, it is valid return(0);
fprintf(stderr,"proof txid.%s\n",proof.first.GetHex().c_str());
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "proof txid=" << proof.first.GetHex() << std::endl);
uint256 sourcetxid = proof.first, hashBlock;
CTransaction sourcetx;
if (!myGetTransaction(sourcetxid, sourcetx, hashBlock)) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "could not load source txid=" << sourcetxid.GetHex() << std::endl);
return -1;
}
if (sourcetx.vout.size() == 0) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "no vouts in source txid=" << sourcetxid.GetHex() << std::endl);
return -1;
}
// might be malleable:
if (burnTx.nExpiryHeight != sourcetx.nExpiryHeight) {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "burntx nExpiryHeight incorrect for source txid=" << sourcetxid.GetHex() << std::endl);
return -1;
}
//ac_pubkey check:
if (CheckVin0PubKey(sourcetx) < 0) {
return -1;
}
// get source tx opret:
std::vector<uint8_t> vopret;
uint8_t evalCode, funcId;
int64_t amount;
GetOpReturnData(sourcetx.vout.back().scriptPubKey, vopret);
if (vopret.size() == 0 || !E_UNMARSHAL(vopret, ss >> evalCode; ss >> funcId; ss >> amount) || evalCode != EVAL_IMPORTCOIN || funcId != 'A') {
LOGSTREAM("importcoin", CCLOG_INFO, stream << "no or incorrect opret to validate in source txid=" << sourcetxid.GetHex() << std::endl);
return -1;
}
LOGSTREAM("importcoin", CCLOG_DEBUG1, stream << "importTx amount=" << payouts[0].nValue << " burnTx amount=" << burnTx.vout[0].nValue << " opret amount=" << amount << " source txid=" << sourcetxid.GetHex() << std::endl);
// amount malleability check with the opret from the source tx:
if (payouts[0].nValue != amount) { // assume that burntx amount is checked in the common code in Eval::ImportCoin()
LOGSTREAM("importcoin", CCLOG_INFO, stream << "importTx amount != amount in the opret of source txid=" << sourcetxid.GetHex() << std::endl);
return -1;
}
return(0);
return(-1);
}
bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &importTx,unsigned int nIn)
@@ -132,10 +415,10 @@ bool Eval::ImportCoin(const std::vector<uint8_t> params,const CTransaction &impo
return Invalid("invalid-params");
// Control all aspects of this transaction
// It should not be at all malleable
if (MakeImportCoinTransaction(proof, burnTx, payouts).GetHash() != importTx.GetHash())
if (MakeImportCoinTransaction(proof, burnTx, payouts, importTx.nExpiryHeight).GetHash() != importTx.GetHash()) // ExistsImportTombstone prevents from duplication
return Invalid("non-canonical");
// burn params
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash,rawproof))
if (!UnmarshalBurnTx(burnTx, targetSymbol, &targetCcid, payoutsHash, rawproof))
return Invalid("invalid-burn-tx");
// check burn amount
{

View File

@@ -35,8 +35,8 @@
* *
******************************************************************************/
#ifndef cJSON__h
#define cJSON__h
#ifndef cJSON__ccih
#define cJSON__ccih
#include <stdio.h>
#include <stdlib.h>

View File

@@ -1 +1,2 @@
gcc -std=c++11 -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../cclib.so cclib.cpp
#!/bin/sh
gcc -std=c++11 -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -c -o ../libcc.so cclib.cpp

8
src/cc/makerogue Executable file
View File

@@ -0,0 +1,8 @@
#!/bin/sh
cd rogue;
./configure # only need this first time
make; cd ..
gcc -Wno-write-strings -DBUILD_ROGUE -std=c++11 -I../../depends/$(shell echo `../..//depends/config.guess`/include) -I../univalue/include -I../cryptoconditions/include -I../cryptoconditions/src -I../cryptoconditions/src/asn -I.. -I. -fPIC -shared -o librogue.so -c cclib.cpp -lncurses
#gcc -std=c++11 -fPIC -shared -o librogue.so cclib.o rogue/rogue.so
cp librogue.so ../libcc.so

View File

@@ -366,7 +366,7 @@ int64_t AddMarmaraCoinbases(struct CCcontract_info *cp,CMutableTransaction &mtx,
{
if ( DecodeMaramaraCoinbaseOpRet(vintx.vout[1].scriptPubKey,pk,ht,unlockht) == 'C' && unlockht == unlocks && pk == poolpk && ht >= firstheight )
{
if ( (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= vintx.vout[vout].nValue) > 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));
@@ -395,7 +395,7 @@ int64_t AddMarmarainputs(CMutableTransaction &mtx,std::vector<CPubKey> &pubkeys,
vout = (int32_t)it->first.index;
if ( it->second.satoshis < threshold )
continue;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && vout < numvouts && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && vout < numvouts && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( (funcid= DecodeMaramaraCoinbaseOpRet(tx.vout[numvouts-1].scriptPubKey,pk,ht,unlockht)) == 'C' || funcid == 'P' || funcid == 'L' )
{
@@ -455,14 +455,16 @@ UniValue MarmaraLock(uint64_t txfee,int64_t amount,int32_t height)
GetCCaddress1of2(cp,coinaddr,Marmarapk,mypk);
SetCCunspents(unspentOutputs,coinaddr);
threshold = remains / (MARMARA_VINS+1);
CCaddr1of2set(cp,Marmarapk,mypk,coinaddr);
uint8_t mypriv[32];
Myprivkey(mypriv);
CCaddr1of2set(cp,Marmarapk,mypk,mypriv,coinaddr);
for (std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> >::const_iterator it=unspentOutputs.begin(); it!=unspentOutputs.end(); it++)
{
txid = it->first.txhash;
vout = (int32_t)it->first.index;
if ( (nValue= it->second.satoshis) < threshold )
continue;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && vout < numvouts && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && (numvouts= tx.vout.size()) > 0 && vout < numvouts && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( (funcid= DecodeMaramaraCoinbaseOpRet(tx.vout[numvouts-1].scriptPubKey,pk,ht,unlockht)) == 'C' || funcid == 'P' || funcid == 'L' )
{

View File

@@ -171,7 +171,7 @@ CPubKey OracleBatonPk(char *batonaddr,struct CCcontract_info *cp)
if ( ctx == 0 )
ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
Myprivkey(priv);
cp->evalcode2 = EVAL_ORACLES;
cp->unspendableEvalcode2 = EVAL_ORACLES;
for (i=0; i<32; i++)
cp->unspendablepriv2[i] = (priv[i] ^ cp->CCpriv[i]);
while ( secp256k1_ec_seckey_verify(ctx,cp->unspendablepriv2) == 0 )
@@ -294,7 +294,7 @@ uint256 OracleBatonUtxo(uint64_t txfee,struct CCcontract_info *cp,uint256 refora
}
}
}
while ( myIsutxo_spentinmempool(batontxid,1) != 0 )
while ( myIsutxo_spentinmempool(ignoretxid,ignorevin,batontxid,1) != 0 )
batontxid = myIs_baton_spentinmempool(batontxid,1);
return(batontxid);
}
@@ -724,7 +724,7 @@ int64_t AddOracleInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,uint
else if (tmporacletxid==oracletxid)
{
// get valid CC payments
if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= IsOraclesvout(cp,vintx,vout)) >= 10000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));

View File

@@ -127,7 +127,7 @@ int64_t AddPaymentsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CP
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsPaymentsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= IsPaymentsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));

View File

@@ -134,7 +134,7 @@ int64_t AddPegsInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,CPubKe
// no need to prevent dup
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 )
{
if ( (nValue= IsPegsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= IsPegsvout(cp,vintx,vout)) > 1000000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));

View File

@@ -13,6 +13,7 @@
* *
******************************************************************************/
#include "CCassets.h"
#include "CCPrices.h"
/*
@@ -89,6 +90,9 @@ uint8_t DecodePricesFundingOpRet(CScript scriptPubKey,CPubKey &planpk,uint256 &o
bool PricesValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &tx, uint32_t nIn)
{
int32_t numvins,numvouts,preventCCvins,preventCCvouts,i,numblocks; bool retval; uint256 txid; uint8_t hash[32]; char str[65],destaddr[64];
return true; // TODO remove, for test dual-evals
return eval->Invalid("no validation yet");
std::vector<std::pair<CAddressIndexKey, CAmount> > txids;
numvins = tx.vin.size();
@@ -141,7 +145,7 @@ int64_t AddTokensInputs(struct CCcontract_info *cp,CMutableTransaction &mtx,char
if ( GetTransaction(txid,vintx,hashBlock,false) != 0 && vout < vintx.vout.size() )
{
// need to verify assetid
if ( (nValue= vintx.vout[vout].nValue) >= 10000 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( (nValue= vintx.vout[vout].nValue) >= 10000 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( total != 0 && maxinputs != 0 )
mtx.vin.push_back(CTxIn(txid,vout,CScript()));

View File

@@ -203,7 +203,7 @@ bool RewardsValidate(struct CCcontract_info *cp,Eval* eval,const CTransaction &t
else
{
txid = tx.GetHash();
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 )
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[numvouts-1].scriptPubKey,sbits,fundingtxid)) != 0 )
{
if ( eval->GetTxUnconfirmed(fundingtxid,fundingTx,hashBlock) == 0 )
return eval->Invalid("cant find fundingtxid");
@@ -310,7 +310,7 @@ static uint64_t myIs_unlockedtx_inmempool(uint256 &txid,int32_t &vout,uint64_t r
if ( tx.vout.size() > 0 && tx.vout[0].nValue >= needed )
{
const uint256 &hash = tx.GetHash();
if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(hash,0) == 0 )
if ( tx.vout[0].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,hash,0) == 0 )
{
if ( (funcid= DecodeRewardsOpRet(hash,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) == 'U' && sbits == refsbits && fundingtxid == reffundingtxid )
{
@@ -346,7 +346,7 @@ int64_t AddRewardsInputs(CScript &scriptPubKey,uint64_t maxseconds,struct CCcont
break;
if ( j != mtx.vin.size() )
continue;
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(txid,vout) == 0 )
if ( GetTransaction(txid,tx,hashBlock,false) != 0 && tx.vout.size() > 0 && tx.vout[vout].scriptPubKey.IsPayToCryptoCondition() != 0 && myIsutxo_spentinmempool(ignoretxid,ignorevin,txid,vout) == 0 )
{
if ( (funcid= DecodeRewardsOpRet(txid,tx.vout[tx.vout.size()-1].scriptPubKey,sbits,fundingtxid)) != 0 )
{

93
src/cc/rogue/LICENSE.TXT Normal file
View File

@@ -0,0 +1,93 @@
Rogue: Exploring the Dungeons of Doom
Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
===========================================================================
Portions of this software (state.c, mdport.c) are based on the work
of Nicholas J. Kisseberth. Used under license:
Copyright (C) 1999, 2000, 2005 Nicholas J. Kisseberth
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
===========================================================================
Portions of this software (xcrypt.c) are based on the work
of David Burren. Used under license:
FreeSec: libcrypt
Copyright (C) 1994 David Burren
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the author(s) nor the names of other contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTORS BE LIABLE
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

220
src/cc/rogue/Makefile.in Normal file
View File

@@ -0,0 +1,220 @@
###############################################################################
#
# Makefile for rogue
#
# Rogue: Exploring the Dungeons of Doom
# Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
# All rights reserved.
#
# See the file LICENSE.TXT for full copyright and licensing information.
#
###############################################################################
###############################################################################
# Site configuration occurs beneath this comment
# Typically ./configure (autoconf tools) configures this section
# This section could be manually configured if autoconf/configure fails
###############################################################################
DISTNAME=@PACKAGE_TARNAME@@PACKAGE_VERSION@
PACKAGE_TARNAME = @PACKAGE_TARNAME@-@PACKAGE_VERSION@
PROGRAM=@PROGRAM@
O=o
#CC=gcc
CC = @CC@
#CFLAGS=-O2
CFLAGS= @CFLAGS@ -fPIC
#LIBS=-lcurses
LIBS = @LIBS@
#RM=rm -f
RM = rm -f
#GROFF=groff
GROFF = @GROFF@
#NROFF=nroff
NROFF = @NROFF@
#TBL=tbl
TBL = @TBL@
#COLCRT=colcrt
COLCRT = @COLCRT@
#SED=sed
SED = @SED@
#SCOREFILE=rogue54.scr
SCOREFILE = @SCOREFILE@
#LOCKFILE=rogue54.lck
LOCKFILE = @LOCKFILE@
#GROUPOWNER=games
GROUPOWNER = @GROUPOWNER@
#CPPFLAGS=-DHAVE_CONFIG_H
CPPFLAGS =@DEFS@ @CPPFLAGS@
#DISTFILE = $(PROGRAM)
DISTFILE = $(DISTNAME)-@TARGET@
INSTALL=./install-sh
#INSTGROUP=-g games
INSTGROUP=
#INSTOWNER=-u root
INSTOWNER=
CHGRP=chgrp
MKDIR=mkdir
TOUCH=touch
RMDIR=rmdir
CHMOD=chmod
DESTDIR=
prefix=@prefix@
exec_prefix=@exec_prefix@
datarootdir=@datarootdir@
datadir=@datadir@
bindir=@bindir@
mandir=@mandir@
docdir=@docdir@
man6dir = $(mandir)/man6
###############################################################################
# Site configuration occurs above this comment
# It should not be necessary to change anything below this comment
###############################################################################
HDRS = rogue.h extern.h score.h
OBJS1 = vers.$(O) extern.$(O) armor.$(O) chase.$(O) command.$(O) \
daemon.$(O) daemons.$(O) fight.$(O) init.$(O) io.$(O) list.$(O) \
mach_dep.$(O) rogue.$(O) mdport.$(O) misc.$(O) monsters.$(O) \
move.$(O) new_level.$(O)
OBJS2 = options.$(O) pack.$(O) passages.$(O) potions.$(O) rings.$(O) \
rip.$(O) rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) \
things.$(O) weapons.$(O) wizard.$(O) xcrypt.$(O)
OBJS = main.$(O) $(OBJS1) $(OBJS2)
CFILES = vers.c extern.c armor.c chase.c command.c daemon.c \
daemons.c fight.c init.c io.c list.c mach_dep.c \
main.c mdport.c misc.c monsters.c move.c new_level.c \
options.c pack.c passages.c potions.c rings.c rip.c \
rooms.c save.c scrolls.c state.c sticks.c things.c \
weapons.c wizard.c xcrypt.c
MISC_C = findpw.c scedit.c scmisc.c
DOCSRC = rogue.me.in rogue.6.in rogue.doc.in rogue.html.in rogue.cat.in
DOCS = $(PROGRAM).doc $(PROGRAM).html $(PROGRAM).cat $(PROGRAM).me \
$(PROGRAM).6
AFILES = configure Makefile.in configure.ac config.h.in config.sub config.guess \
install-sh rogue.6.in rogue.me.in rogue.html.in rogue.doc.in rogue.cat.in
MISC = Makefile.std LICENSE.TXT rogue54.sln rogue54.vcproj rogue.spec \
rogue.png rogue.desktop
.SUFFIXES: .obj
.c.obj:
$(CC) $(CFLAGS) $(CPPFLAGS) /c $*.c
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) -c $*.c
$(PROGRAM): $(HDRS) $(OBJS)
$(RM) rogue.so ; $(CC) -shared -o rogue.so $(OBJS1) $(OBJS2) -lcurses; $(CC) $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) -o $@
clean:
$(RM) $(OBJS1); $(RM) main.$(O) ; $(RM) rogue.so
$(RM) $(OBJS2)
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe
$(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip
$(RM) $(DISTNAME)/*
-rmdir $(DISTNAME)
maintainer-clean:
$(RM) config.h
$(RM) Makefile
$(RM) config.status
$(RM) -r autom4te.cache
$(RM) config.log
$(RM) $(PROGRAM).scr $(PROGRAM).lck
stddocs:
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.6.in > rogue.6
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.me.in > rogue.me
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.html.in > rogue,html
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.doc.in > rogue.doc
sed -e 's/@PROGRAM@/rogue/' -e 's/@SCOREFILE@/rogue.scr/' rogue.cat.in > rogue.cat
dist.src:
$(MAKE) $(MAKEFILE) clean
mkdir $(DISTNAME)
cp $(CFILES) $(HDRS) $(MISC) $(AFILES) $(DISTNAME)
tar cf $(DISTNAME)-src.tar $(DISTNAME)
gzip -f $(DISTNAME)-src.tar
rm -fr $(DISTNAME)
findpw: findpw.c xcrypt.o mdport.o xcrypt.o
$(CC) -s -o findpw findpw.c xcrypt.o mdport.o -lcurses
scedit: scedit.o scmisc.o vers.o mdport.o xcrypt.o
$(CC) -s -o scedit vers.o scedit.o scmisc.o mdport.o xcrypt.o -lcurses
scmisc.o scedit.o:
$(CC) -O -c $(SF) $*.c
$(PROGRAM).doc: rogue.me
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \
$(GROFF) -P-c -t -me -Tascii rogue.me | $(SED) -e 's/.\x08//g' > $(PROGRAM).doc ;\
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \
tbl rogue.me | $(NROFF) -me | colcrt - > $(PROGRAM).doc ;\
fi
$(PROGRAM).cat: rogue.6
if test "x$(GROFF)" != "x" -a "x$(SED)" != "x" ; then \
$(GROFF) -Tascii -man rogue.6 | $(SED) -e 's/.\x08//g' > $(PROGRAM).cat ;\
elif test "x$(NROFF)" != "x" -a "x$(TBL)" != "x" -a "x$(COLCRT)" != "x" ; then \
$(NROFF) -man rogue.6 | $(COLCRT) - > $(PROGRAM).cat ;\
fi
dist: clean $(PROGRAM)
tar cf $(DISTFILE).tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTFILE).tar
install: $(PROGRAM)
-$(TOUCH) test
-if test ! -f $(DESTDIR)$(SCOREFILE) ; then $(INSTALL) -m 0664 test $(DESTDIR)$(SCOREFILE) ; fi
-$(INSTALL) -m 0755 $(PROGRAM) $(DESTDIR)$(bindir)/$(PROGRAM)
-if test "x$(GROUPOWNER)" != "x" ; then \
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(SCOREFILE) ; \
$(CHGRP) $(GROUPOWNER) $(DESTDIR)$(bindir)/$(PROGRAM) ; \
$(CHMOD) 02755 $(DESTDIR)$(bindir)/$(PROGRAM) ; \
$(CHMOD) 0464 $(DESTDIR)$(SCOREFILE) ; \
fi
-if test -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(man6dir)/$(PROGRAM).6 ; fi
-if test ! -d $(man6dir) ; then $(INSTALL) -m 0644 rogue.6 $(DESTDIR)$(mandir)/$(PROGRAM).6 ; fi
-$(INSTALL) -m 0644 rogue.doc $(DESTDIR)$(docdir)/$(PROGRAM).doc
-$(INSTALL) -m 0644 rogue.html $(DESTDIR)$(docdir)/$(PROGRAM).html
-$(INSTALL) -m 0644 rogue.cat $(DESTDIR)$(docdir)/$(PROGRAM).cat
-$(INSTALL) -m 0644 LICENSE.TXT $(DESTDIR)$(docdir)/LICENSE.TXT
-$(INSTALL) -m 0644 rogue.me $(DESTDIR)$(docdir)/$(PROGRAM).me
-if test ! -f $(DESTDIR)$(LOCKFILE) ; then $(INSTALL) -m 0666 test $(DESTDIR)$(LOCKFILE) ; $(RM) $(DESTDIR)$(LOCKFILE) ; fi
-$(RM) test
uninstall:
-$(RM) $(DESTDIR)$(bindir)/$(PROGRAM)
-$(RM) $(DESTDIR)$(man6dir)/$(PROGRAM).6
-$(RM) $(DESTDIR)$(docdir)$(PROGRAM)/$(PROGRAM).doc
-$(RM) $(DESTDIR)$(LOCKFILE)
-$(RMDIR) $(DESTDIR)$(docdir)$(PROGRAM)
reinstall: uninstall install

158
src/cc/rogue/Makefile.std Executable file
View File

@@ -0,0 +1,158 @@
#
# Makefile for rogue
# @(#)Makefile 4.21 (Berkeley) 02/04/99
#
# Rogue: Exploring the Dungeons of Doom
# Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
# All rights reserved.
#
# See the file LICENSE.TXT for full copyright and licensing information.
#
DISTNAME = rogue5.4.4
PROGRAM = rogue54
O = o
HDRS = rogue.h extern.h score.h
OBJS1 = vers.$(O) extern.$(O) armor.$(O) chase.$(O) command.$(O) \
daemon.$(O) daemons.$(O) fight.$(O) init.$(O) io.$(O) list.$(O) \
mach_dep.$(O) main.$(O) mdport.$(O) misc.$(O) monsters.$(O) \
move.$(O) new_level.$(O)
OBJS2 = options.$(O) pack.$(O) passages.$(O) potions.$(O) rings.$(O) \
rip.$(O) rooms.$(O) save.$(O) scrolls.$(O) state.$(O) sticks.$(O) \
things.$(O) weapons.$(O) wizard.$(O) xcrypt.$(O)
OBJS = $(OBJS1) $(OBJS2)
CFILES = vers.c extern.c armor.c chase.c command.c daemon.c \
daemons.c fight.c init.c io.c list.c mach_dep.c \
main.c mdport.c misc.c monsters.c move.c new_level.c \
options.c pack.c passages.c potions.c rings.c rip.c \
rooms.c save.c scrolls.c state.c sticks.c things.c \
weapons.c wizard.c xcrypt.c
MISC_C = findpw.c scedit.c scmisc.c
DOCSRC = rogue.me.in rogue.6.in rogue.doc.in rogue.html.in rogue.cat.in
DOCS = $(PROGRAM).doc $(PROGRAM).html $(PROGRAM).cat $(PROGRAM).me \
$(PROGRAM).6
AFILES = configure Makefile.in configure.ac config.h.in config.sub config.guess \
install-sh rogue.6.in rogue.me.in rogue.html.in rogue.doc.in rogue.cat.in
MISC = Makefile.std LICENSE.TXT rogue54.sln rogue54.vcproj rogue.spec \
rogue.png rogue.desktop
CC = gcc
FEATURES = -DALLSCORES -DSCOREFILE=\"$(SCOREFILE)\" -DLOCKFILE=\"$(LOCKFILE)\"
CPPFLAGS =
CFLAGS = -O3
LDFLAGS =
LIBS = -lcurses
RM = rm -f
MAKEFILE = -f Makefile.std
SCOREFILE= $(PROGRAM).scr
LOCKFILE = $(PROGRAM).lck
OUTFLAG = -o
EXE =
.SUFFIXES: .obj
.c.obj:
$(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURES) /c $*.c
.c.o:
$(CC) $(CFLAGS) $(CPPFLAGS) $(FEATURES) -c $*.c
$(PROGRAM): $(HDRS) $(OBJS) fixdocs
$(CC) $(LDFLAGS) $(OBJS) $(LIBS) $(OUTFLAG)$@$(EXE)
clean:
$(RM) $(OBJS1)
$(RM) $(OBJS2)
$(RM) core a.exe a.out a.exe.stackdump $(PROGRAM) $(PROGRAM).exe $(PROGRAM).lck
$(RM) $(PROGRAM).tar $(PROGRAM).tar.gz $(PROGRAM).zip
$(RM) $(DISTNAME)/*
dist.src:
$(MAKE) $(MAKEFILE) clean
mkdir $(DISTNAME)
cp $(CFILES) $(HDRS) $(MISC) $(AFILES) $(DISTNAME)
tar cf $(DISTNAME)-src.tar $(DISTNAME)
gzip -f $(DISTNAME)-src.tar
rm -fr $(DISTNAME)
findpw: findpw.c xcrypt.o mdport.o xcrypt.o
$(CC) -s -o findpw findpw.c xcrypt.o mdport.o -lcurses
scedit: scedit.o scmisc.o vers.o mdport.o xcrypt.o
$(CC) -s -o scedit vers.o scedit.o scmisc.o mdport.o xcrypt.o -lcurses
scmisc.o scedit.o:
$(CC) -O -c $(SF) $*.c
doc.nroff:
tbl rogue.me | nroff -me | colcrt - > rogue.doc
nroff -man rogue.6 | colcrt - > rogue.cat
doc.groff:
groff -P-c -t -me -Tascii rogue.me | sed -e 's/.\x08//g' > rogue.doc
groff -man rogue.6 | sed -e 's/.\x08//g' > rogue.cat
fixdocs:
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.6.in > $(PROGRAM).6
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.me.in > $(PROGRAM).me
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.html.in > $(PROGRAM).html
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.doc.in > $(PROGRAM).doc
sed -e 's/@PROGRAM@/$(PROGRAM)/' -e 's/@SCOREFILE@/$(SCOREFILE)/' rogue.cat.in > $(PROGRAM).cat
dist.irix:
$(MAKE) $(MAKEFILE) clean
$(MAKE) $(MAKEFILE) CC=cc $(PROGRAM)
tar cf $(DISTNAME)-irix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-irix.tar
dist.aix:
$(MAKE) $(MAKEFILE) clean
$(MAKE) $(MAKEFILE) CC=xlc CFLAGS="-qmaxmem=16768 -O3 -qstrict" $(PROGRAM)
tar cf $(DISTNAME)-aix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-aix.tar
dist.linux:
$(MAKE) $(MAKEFILE) clean
$(MAKE) $(MAKEFILE) $(PROGRAM)
tar cf $(DISTNAME)-linux.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-linux.tar
dist.interix:
@$(MAKE) $(MAKEFILE) clean
@$(MAKE) $(MAKEFILE) CFLAGS="-ansi" $(PROGRAM)
tar cf $(DISTNAME)-interix.tar $(PROGRAM) LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-interix.tar
dist.cygwin:
@$(MAKE) $(MAKEFILE) --no-print-directory clean
@$(MAKE) $(MAKEFILE) CPPFLAGS="-I/usr/include/ncurses" --no-print-directory $(PROGRAM)
tar cf $(DISTNAME)-cygwin.tar $(PROGRAM).exe LICENSE.TXT $(DOCS)
gzip -f $(DISTNAME)-cygwin.tar
#
# Use MINGW32-MAKE to build this target
#
dist.mingw32:
@$(MAKE) $(MAKEFILE) --no-print-directory RM="cmd /c del" clean
@$(MAKE) $(MAKEFILE) --no-print-directory CPPFLAGS="-I../pdcurses" LIBS="../pdcurses/pdcurses.a" $(PROGRAM)
cmd /c del $(DISTNAME)-mingw32.zip
zip $(DISTNAME)-mingw32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)
dist.djgpp:
@$(MAKE) $(MAKEFILE) --no-print-directory clean
@$(MAKE) $(MAKEFILE) --no-print-directory LDFLAGS="-L$(DJDIR)/LIB" \
LIBS="-lpdcurses" $(PROGRAM)
rm -f $(DISTNAME)-djgpp.zip
zip $(DISTNAME)-djgpp.zip $(PROGRAM) LICENSE.TXT $(DOCS)
#
# Use NMAKE to build this targer
#
dist.win32:
@$(MAKE) $(MAKEFILE) /NOLOGO O="obj" RM="-del" clean
@$(MAKE) $(MAKEFILE) /NOLOGO O="obj" CC="CL" \
LIBS="..\pdcurses\pdcurses.lib shell32.lib user32.lib Advapi32.lib" \
EXE=".exe" OUTFLAG="/Fe" CPPFLAGS="-I..\pdcurses" \
CFLAGS="-nologo -Ox -wd4033 -wd4716" $(PROGRAM)
-del $(DISTNAME)-win32.zip
zip $(DISTNAME)-win32.zip $(PROGRAM).exe LICENSE.TXT $(DOCS)

89
src/cc/rogue/armor.c Normal file
View File

@@ -0,0 +1,89 @@
/*
* This file contains misc functions for dealing with armor
* @(#)armor.c 4.14 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <curses.h>
#include "rogue.h"
/*
* wear:
* The player wants to wear something, so let him/her put it on.
*/
void
wear(struct rogue_state *rs)
{
register THING *obj;
register char *sp;
if ((obj = get_item(rs,"wear", ARMOR)) == NULL)
return;
if (cur_armor != NULL)
{
addmsg(rs,"you are already wearing some");
if (!terse)
addmsg(rs,". You'll have to take it off first");
endmsg(rs);
after = FALSE;
return;
}
if (obj->o_type != ARMOR)
{
msg(rs,"you can't wear that");
return;
}
waste_time(rs);
obj->o_flags |= ISKNOW;
sp = inv_name(obj, TRUE);
cur_armor = obj;
if (!terse)
addmsg(rs,"you are now ");
msg(rs,"wearing %s", sp);
}
/*
* take_off:
* Get the armor off of the players back
*/
void
take_off(struct rogue_state *rs)
{
register THING *obj;
if ((obj = cur_armor) == NULL)
{
after = FALSE;
if (terse)
msg(rs,"not wearing armor");
else
msg(rs,"you aren't wearing any armor");
return;
}
if (!dropcheck(rs,cur_armor))
return;
cur_armor = NULL;
if (terse)
addmsg(rs,"was");
else
addmsg(rs,"you used to be");
msg(rs," wearing %c) %s", obj->o_packch, inv_name(obj, TRUE));
}
/*
* waste_time:
* Do nothing but let other things happen
*/
void
waste_time(struct rogue_state *rs)
{
do_daemons(rs,BEFORE);
do_fuses(rs,BEFORE);
do_daemons(rs,AFTER);
do_fuses(rs,AFTER);
}

541
src/cc/rogue/chase.c Normal file
View File

@@ -0,0 +1,541 @@
/*
* Code for one creature to chase another
*
* @(#)chase.c 4.57 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <stdlib.h>
//#include <curses.h>
#include "rogue.h"
#define DRAGONSHOT 5 /* one chance in DRAGONSHOT that a dragon will flame */
static coord ch_ret; /* Where chasing takes you */
/*
* runners:
* Make all the running monsters move.
*/
void
runners(struct rogue_state *rs,int arg)
{
register THING *tp;
THING *next;
bool wastarget;
static coord orig_pos;
for (tp = mlist; tp != NULL; tp = next)
{
/* remember this in case the monster's "next" is changed */
next = next(tp);
if (!on(*tp, ISHELD) && on(*tp, ISRUN))
{
orig_pos = tp->t_pos;
wastarget = on(*tp, ISTARGET);
if (move_monst(rs,tp) == -1)
continue;
if (on(*tp, ISFLY) && dist_cp(&hero, &tp->t_pos) >= 3)
move_monst(rs,tp);
if (wastarget && !ce(orig_pos, tp->t_pos))
{
tp->t_flags &= ~ISTARGET;
to_death = FALSE;
}
}
}
if (has_hit)
{
endmsg(rs);
has_hit = FALSE;
}
}
/*
* move_monst:
* Execute a single turn of running for a monster
*/
int
move_monst(struct rogue_state *rs,THING *tp)
{
if (!on(*tp, ISSLOW) || tp->t_turn)
if (do_chase(rs,tp) == -1)
return(-1);
if (on(*tp, ISHASTE))
if (do_chase(rs,tp) == -1)
return(-1);
tp->t_turn ^= TRUE;
return(0);
}
/*
* relocate:
* Make the monster's new location be the specified one, updating
* all the relevant state.
*/
void
relocate(struct rogue_state *rs,THING *th, coord *new_loc)
{
struct room *oroom;
if (!ce(*new_loc, th->t_pos))
{
mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch);
th->t_room = roomin(rs,new_loc);
set_oldch(th, new_loc);
oroom = th->t_room;
moat(th->t_pos.y, th->t_pos.x) = NULL;
if (oroom != th->t_room)
th->t_dest = find_dest(rs,th);
th->t_pos = *new_loc;
moat(new_loc->y, new_loc->x) = th;
}
move(new_loc->y, new_loc->x);
if (see_monst(th))
addch(th->t_disguise);
else if (on(player, SEEMONST))
{
standout();
addch(th->t_type);
standend();
}
}
/*
* do_chase:
* Make one thing chase another.
*/
int
do_chase(struct rogue_state *rs,THING *th)
{
register coord *cp;
register struct room *rer, *ree; /* room of chaser, room of chasee */
register int mindist = 32767, curdist;
register bool stoprun = FALSE; /* TRUE means we are there */
register bool door;
register THING *obj;
static coord DEST; /* Temporary destination for chaser */
rer = th->t_room; /* Find room of chaser */
if (on(*th, ISGREED) && rer->r_goldval == 0)
th->t_dest = &hero; /* If gold has been taken, run after hero */
if (th->t_dest == &hero) /* Find room of chasee */
ree = proom;
else
ree = roomin(rs,th->t_dest);
/*
* We don't count doors as inside rooms for this routine
*/
door = (chat(th->t_pos.y, th->t_pos.x) == DOOR);
/*
* If the object of our desire is in a different room,
* and we are not in a corridor, run to the door nearest to
* our goal.
*/
over:
if (rer != ree)
{
for (cp = rer->r_exit; cp < &rer->r_exit[rer->r_nexits]; cp++)
{
curdist = dist_cp(th->t_dest, cp);
if (curdist < mindist)
{
DEST = *cp;
mindist = curdist;
}
}
if (door)
{
rer = &passages[flat(th->t_pos.y, th->t_pos.x) & F_PNUM];
door = FALSE;
goto over;
}
}
else
{
DEST = *th->t_dest;
/*
* For dragons check and see if (a) the hero is on a straight
* line from it, and (b) that it is within shooting distance,
* but outside of striking range.
*/
if (th->t_type == 'D' && (th->t_pos.y == hero.y || th->t_pos.x == hero.x
|| abs(th->t_pos.y - hero.y) == abs(th->t_pos.x - hero.x))
&& dist_cp(&th->t_pos, &hero) <= BOLT_LENGTH * BOLT_LENGTH
&& !on(*th, ISCANC) && rnd(DRAGONSHOT) == 0)
{
delta.y = sign(hero.y - th->t_pos.y);
delta.x = sign(hero.x - th->t_pos.x);
if (has_hit)
endmsg(rs);
fire_bolt(rs,&th->t_pos, &delta, "flame");
running = FALSE;
count = 0;
quiet = 0;
if (to_death && !on(*th, ISTARGET))
{
to_death = FALSE;
kamikaze = FALSE;
}
return(0);
}
}
/*
* This now contains what we want to run to this time
* so we run to it. If we hit it we either want to fight it
* or stop running
*/
if (!chase(th, &DEST))
{
if (ce(DEST, hero))
{
return( attack(rs,th) );
}
else if (ce(DEST, *th->t_dest))
{
for (obj = lvl_obj; obj != NULL; obj = next(obj))
if (th->t_dest == &obj->o_pos)
{
detach(lvl_obj, obj);
attach(th->t_pack, obj);
chat(obj->o_pos.y, obj->o_pos.x) =
(th->t_room->r_flags & ISGONE) ? PASSAGE : FLOOR;
th->t_dest = find_dest(rs,th);
break;
}
if (th->t_type != 'F')
stoprun = TRUE;
}
}
else
{
if (th->t_type == 'F')
return(0);
}
relocate(rs,th, &ch_ret);
/*
* And stop running if need be
*/
if (stoprun && ce(th->t_pos, *(th->t_dest)))
th->t_flags &= ~ISRUN;
return(0);
}
/*
* set_oldch:
* Set the oldch character for the monster
*/
void
set_oldch(THING *tp, coord *cp)
{
char sch;
if (ce(tp->t_pos, *cp))
return;
sch = tp->t_oldch;
tp->t_oldch = CCHAR( mvinch(cp->y,cp->x) );
if (!on(player, ISBLIND))
{
if ((sch == FLOOR || tp->t_oldch == FLOOR) &&
(tp->t_room->r_flags & ISDARK))
tp->t_oldch = ' ';
else if (dist_cp(cp, &hero) <= LAMPDIST && see_floor)
tp->t_oldch = chat(cp->y, cp->x);
}
}
/*
* see_monst:
* Return TRUE if the hero can see the monster
*/
bool
see_monst(THING *mp)
{
int y, x;
if (on(player, ISBLIND))
return FALSE;
if (on(*mp, ISINVIS) && !on(player, CANSEE))
return FALSE;
y = mp->t_pos.y;
x = mp->t_pos.x;
if (dist(y, x, hero.y, hero.x) < LAMPDIST)
{
if (y != hero.y && x != hero.x &&
!step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x)))
return FALSE;
return TRUE;
}
if (mp->t_room != proom)
return FALSE;
return ((bool)!(mp->t_room->r_flags & ISDARK));
}
/*
* runto:
* Set a monster running after the hero.
*/
void
runto(struct rogue_state *rs,coord *runner)
{
register THING *tp;
/*
* If we couldn't find him, something is funny
*/
#ifdef MASTER
if ((tp = moat(runner->y, runner->x)) == NULL)
msg(rs,"couldn't find monster in runto at (%d,%d)", runner->y, runner->x);
#else
tp = moat(runner->y, runner->x);
#endif
/*
* Start the beastie running
*/
tp->t_flags |= ISRUN;
tp->t_flags &= ~ISHELD;
tp->t_dest = find_dest(rs,tp);
}
/*
* chase:
* Find the spot for the chaser(er) to move closer to the
* chasee(ee). Returns TRUE if we want to keep on chasing later
* FALSE if we reach the goal.
*/
bool
chase(THING *tp, coord *ee)
{
register THING *obj;
register int x, y;
register int curdist, thisdist;
register coord *er = &tp->t_pos;
register char ch;
register int plcnt = 1;
static coord tryp;
/*
* If the thing is confused, let it move randomly. Invisible
* Stalkers are slightly confused all of the time, and bats are
* quite confused all the time
*/
if ((on(*tp, ISHUH) && rnd(5) != 0) || (tp->t_type == 'P' && rnd(5) == 0)
|| (tp->t_type == 'B' && rnd(2) == 0))
{
/*
* get a valid random move
*/
ch_ret = *rndmove(tp);
curdist = dist_cp(&ch_ret, ee);
/*
* Small chance that it will become un-confused
*/
if (rnd(20) == 0)
tp->t_flags &= ~ISHUH;
}
/*
* Otherwise, find the empty spot next to the chaser that is
* closest to the chasee.
*/
else
{
register int ey, ex;
/*
* This will eventually hold where we move to get closer
* If we can't find an empty spot, we stay where we are.
*/
curdist = dist_cp(er, ee);
ch_ret = *er;
ey = er->y + 1;
if (ey >= NUMLINES - 1)
ey = NUMLINES - 2;
ex = er->x + 1;
if (ex >= NUMCOLS)
ex = NUMCOLS - 1;
for (x = er->x - 1; x <= ex; x++)
{
if (x < 0)
continue;
tryp.x = x;
for (y = er->y - 1; y <= ey; y++)
{
tryp.y = y;
if (!diag_ok(er, &tryp))
continue;
ch = winat(y, x);
if (step_ok(ch))
{
/*
* If it is a scroll, it might be a scare monster scroll
* so we need to look it up to see what type it is.
*/
if (ch == SCROLL)
{
for (obj = lvl_obj; obj != NULL; obj = next(obj))
{
if (y == obj->o_pos.y && x == obj->o_pos.x)
break;
}
if (obj != NULL && obj->o_which == S_SCARE)
continue;
}
/*
* It can also be a Xeroc, which we shouldn't step on
*/
if ((obj = moat(y, x)) != NULL && obj->t_type == 'X')
continue;
/*
* If we didn't find any scrolls at this place or it
* wasn't a scare scroll, then this place counts
*/
thisdist = dist(y, x, ee->y, ee->x);
if (thisdist < curdist)
{
plcnt = 1;
ch_ret = tryp;
curdist = thisdist;
}
else if (thisdist == curdist && rnd(++plcnt) == 0)
{
ch_ret = tryp;
curdist = thisdist;
}
}
}
}
}
return (bool)(curdist != 0 && !ce(ch_ret, hero));
}
/*
* roomin:
* Find what room some coordinates are in. NULL means they aren't
* in any room.
*/
struct room *
roomin(struct rogue_state *rs,coord *cp)
{
register struct room *rp;
register char *fp;
fp = &flat(cp->y, cp->x);
if (*fp & F_PASS)
return &passages[*fp & F_PNUM];
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
if (cp->x <= rp->r_pos.x + rp->r_max.x && rp->r_pos.x <= cp->x
&& cp->y <= rp->r_pos.y + rp->r_max.y && rp->r_pos.y <= cp->y)
return rp;
msg(rs,"in some bizarre place (%d, %d)", unc(*cp));
#ifdef MASTER
abort();
return NULL;
#else
return NULL;
#endif
}
/*
* diag_ok:
* Check to see if the move is legal if it is diagonal
*/
bool
diag_ok(coord *sp, coord *ep)
{
if (ep->x < 0 || ep->x >= NUMCOLS || ep->y <= 0 || ep->y >= NUMLINES - 1)
return FALSE;
if (ep->x == sp->x || ep->y == sp->y)
return TRUE;
return (bool)(step_ok(chat(ep->y, sp->x)) && step_ok(chat(sp->y, ep->x)));
}
/*
* cansee:
* Returns true if the hero can see a certain coordinate.
*/
bool
cansee(struct rogue_state *rs,int y, int x)
{
register struct room *rer;
static coord tp;
if (on(player, ISBLIND))
return FALSE;
if (dist(y, x, hero.y, hero.x) < LAMPDIST)
{
if (flat(y, x) & F_PASS)
if (y != hero.y && x != hero.x &&
!step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x)))
return FALSE;
return TRUE;
}
/*
* We can only see if the hero in the same room as
* the coordinate and the room is lit or if it is close.
*/
tp.y = y;
tp.x = x;
return (bool)((rer = roomin(rs,&tp)) == proom && !(rer->r_flags & ISDARK));
}
/*
* find_dest:
* find the proper destination for the monster
*/
coord *
find_dest(struct rogue_state *rs,THING *tp)
{
register THING *obj;
register int prob;
if ((prob = monsters[tp->t_type - 'A'].m_carry) <= 0 || tp->t_room == proom
|| see_monst(tp))
return &hero;
for (obj = lvl_obj; obj != NULL; obj = next(obj))
{
if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
continue;
if (roomin(rs,&obj->o_pos) == tp->t_room && rnd(100) < prob)
{
for (tp = mlist; tp != NULL; tp = next(tp))
if (tp->t_dest == &obj->o_pos)
break;
if (tp == NULL)
return &obj->o_pos;
}
}
return &hero;
}
/*
* dist:
* Calculate the "distance" between to points. Actually,
* this calculates d^2, not d, but that's good enough for
* our purposes, since it's only used comparitively.
*/
int
dist(int y1, int x1, int y2, int x2)
{
return ((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
}
/*
* dist_cp:
* Call dist() with appropriate arguments for coord pointers
*/
int
dist_cp(coord *c1, coord *c2)
{
return dist(c1->y, c1->x, c2->y, c2->x);
}

841
src/cc/rogue/command.c Normal file
View File

@@ -0,0 +1,841 @@
/*
* Read and execute the user commands
*
* @(#)command.c 4.73 (Berkeley) 08/06/83
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <curses.h>
#include "rogue.h"
/*
* command:
* Process the user commands
*/
void
command(struct rogue_state *rs)
{
register char ch;
register int ntimes = 1; /* Number of player moves */
char *fp;
THING *mp;
static char countch, direction, newcount = FALSE;
if (on(player, ISHASTE))
ntimes++;
/*
* Let the daemons start up
*/
do_daemons(rs,BEFORE);
do_fuses(rs,BEFORE);
while (ntimes--)
{
if ( rs->replaydone != 0 )
return;
again = FALSE;
if (has_hit)
{
endmsg(rs);
has_hit = FALSE;
}
/*
* these are illegal things for the player to be, so if any are
* set, someone's been poking in memeory
*/
if (on(player, ISSLOW|ISGREED|ISINVIS|ISREGEN|ISTARGET))
exit(1);
look(rs,TRUE);
if (!running)
door_stop = FALSE;
status(rs);
lastscore = purse;
move(hero.y, hero.x);
if ( rs->sleeptime != 0 )
{
if (!((running || count) && jump))
refresh(); /* Draw screen */
}
take = 0;
after = TRUE;
/*
* Read command or continue run
*/
#ifdef MASTER
if (wizard)
noscore = TRUE;
#endif
if (!no_command)
{
if (running || to_death)
ch = runch;
else if (count)
ch = countch;
else
{
ch = readchar(rs);
move_on = FALSE;
if (mpos != 0) /* Erase message if its there */
msg(rs,"");
}
}
else
ch = '.';
if (no_command)
{
if (--no_command == 0)
{
player.t_flags |= ISRUN;
msg(rs,"you can move again");
}
}
else
{
/*
* check for prefixes
*/
newcount = FALSE;
if (isdigit(ch))
{
count = 0;
newcount = TRUE;
while (isdigit(ch))
{
count = count * 10 + (ch - '0');
if (count > 255)
count = 255;
ch = readchar(rs);
}
countch = ch;
/*
* turn off count for commands which don't make sense
* to repeat
*/
if ( rs->guiflag == 0 && rs->replaydone != 0 )
ch = 'Q';
switch (ch)
{
case CTRL('B'): case CTRL('H'): case CTRL('J'):
case CTRL('K'): case CTRL('L'): case CTRL('N'):
case CTRL('U'): case CTRL('Y'):
case '.': case 'a': case 'b': case 'h': case 'j':
case 'k': case 'l': case 'm': case 'n': case 'q':
case 'r': case 's': case 't': case 'u': case 'y':
case 'z': case 'B': case 'C': case 'H': case 'I':
case 'J': case 'K': case 'L': case 'N': case 'U':
case 'Y':
#ifdef MASTER
case CTRL('D'): case CTRL('A'):
#endif
break;
default:
count = 0;
}
}
/*
* execute a command
*/
if (count && !running)
count--;
if (ch != 'a' && ch != ESCAPE && !(running || count || to_death))
{
l_last_comm = last_comm;
l_last_dir = last_dir;
l_last_pick = last_pick;
last_comm = ch;
last_dir = '\0';
last_pick = NULL;
}
over:
switch (ch)
{
case ',': {
THING *obj = NULL;
int found = 0;
for (obj = lvl_obj; obj != NULL; obj = next(obj))
{
if (obj->o_pos.y == hero.y && obj->o_pos.x == hero.x)
{
found=1;
break;
}
}
if (found) {
if (levit_check(rs))
;
else
pick_up(rs,(char)obj->o_type);
}
else {
if (!terse)
addmsg(rs,"there is ");
addmsg(rs,"nothing here");
if (!terse)
addmsg(rs," to pick up");
endmsg(rs);
}
}
when '!': shell(rs);
when 'h': do_move(rs,0, -1);
when 'j': do_move(rs,1, 0);
when 'k': do_move(rs,-1, 0);
when 'l': do_move(rs,0, 1);
when 'y': do_move(rs,-1, -1);
when 'u': do_move(rs,-1, 1);
when 'b': do_move(rs,1, -1);
when 'n': do_move(rs,1, 1);
when 'H': do_run('h');
when 'J': do_run('j');
when 'K': do_run('k');
when 'L': do_run('l');
when 'Y': do_run('y');
when 'U': do_run('u');
when 'B': do_run('b');
when 'N': do_run('n');
when CTRL('H'): case CTRL('J'): case CTRL('K'): case CTRL('L'):
case CTRL('Y'): case CTRL('U'): case CTRL('B'): case CTRL('N'):
{
if (!on(player, ISBLIND))
{
door_stop = TRUE;
firstmove = TRUE;
}
if (count && !newcount)
ch = direction;
else
{
ch += ('A' - CTRL('A'));
direction = ch;
}
goto over;
}
when 'F':
kamikaze = TRUE;
/* FALLTHROUGH */
case 'f':
if (!get_dir(rs))
{
after = FALSE;
break;
}
delta.y += hero.y;
delta.x += hero.x;
if ( ((mp = moat(delta.y, delta.x)) == NULL)
|| ((!see_monst(mp)) && !on(player, SEEMONST)))
{
if (!terse)
addmsg(rs,"I see ");
msg(rs,"no monster there");
after = FALSE;
}
else if (diag_ok(&hero, &delta))
{
to_death = TRUE;
max_hit = 0;
mp->t_flags |= ISTARGET;
runch = ch = dir_ch;
goto over;
}
when 't':
if (!get_dir(rs))
after = FALSE;
else
missile(rs,delta.y, delta.x);
when 'a':
if (last_comm == '\0')
{
msg(rs,"you haven't typed a command yet");
after = FALSE;
}
else
{
ch = last_comm;
again = TRUE;
goto over;
}
when 'q': quaff(rs);
when 'Q':
after = FALSE;
q_comm = TRUE;
quit(0);
if ( rs->guiflag != 0 && rs->needflush == 0 )
rs->needflush = (uint32_t)time(NULL);
q_comm = FALSE;
if ( rs->guiflag != 0 )
rogue_bailout(rs);
else rs->replaydone = (uint32_t)time(NULL);
return;
when 'i': after = FALSE; inventory(rs,pack, 0);
when 'I': after = FALSE; picky_inven(rs);
when 'd': drop(rs);
when 'r': read_scroll(rs);
when 'e': eat(rs);
when 'w': wield(rs);
when 'W': wear(rs);
when 'T': take_off(rs);
when 'P': ring_on(rs);
when 'R': ring_off(rs);
when 'o': option(rs); after = FALSE;
when 'c': call(rs); after = FALSE;
when '>': after = FALSE; d_level(rs);
if ( rs->guiflag != 0 && rs->needflush == 0 )
rs->needflush = (uint32_t)time(NULL);
when '<': after = FALSE; u_level(rs);
if ( rs->guiflag != 0 && rs->needflush == 0 )
rs->needflush = (uint32_t)time(NULL);
when '?': after = FALSE; help(rs);
when '/': after = FALSE; identify(rs);
when 's': search(rs);
when 'z':
if (get_dir(rs))
do_zap(rs);
else
after = FALSE;
when 'D': after = FALSE; discovered(rs);
when CTRL('P'): after = FALSE; msg(rs,huh);
when CTRL('R'):
after = FALSE;
clearok(curscr,TRUE);
wrefresh(curscr);
when 'v':
after = FALSE;
msg(rs,"version %s. (mctesq was here)", release);
when 'S':
after = FALSE;
#ifdef STANDALONE
save_game(rs);
#else
msg(rs,"Saving is disabled, use bailout rpc");
#endif
when '.': ; /* Rest command */
when ' ': after = FALSE; /* "Legal" illegal command */
when '^':
after = FALSE;
if (get_dir(rs)) {
delta.y += hero.y;
delta.x += hero.x;
fp = &flat(delta.y, delta.x);
if (!terse)
addmsg(rs,"You have found ");
if (chat(delta.y, delta.x) != TRAP)
msg(rs,"no trap there");
else if (on(player, ISHALU))
msg(rs,(char *)tr_name[rnd(NTRAPS)]);
else {
msg(rs,(char *)tr_name[*fp & F_TMASK]);
*fp |= F_SEEN;
}
}
#ifdef MASTER
when '+':
after = FALSE;
if (wizard)
{
wizard = FALSE;
turn_see(TRUE);
msg(rs,"not wizard any more");
}
else
{
wizard = passwd();
if (wizard)
{
noscore = TRUE;
turn_see(FALSE);
msg(rs,"you are suddenly as smart as Ken Arnold in dungeon #%d", dnum);
}
else
msg(rs,"sorry");
}
#endif
when ESCAPE: /* Escape */
door_stop = FALSE;
count = 0;
after = FALSE;
again = FALSE;
when 'm':
move_on = TRUE;
if (!get_dir(rs))
after = FALSE;
else
{
ch = dir_ch;
countch = dir_ch;
goto over;
}
when ')': current(rs,cur_weapon, "wielding", NULL);
when ']': current(rs,cur_armor, "wearing", NULL);
when '=':
current(rs,cur_ring[LEFT], "wearing",
terse ? (char *)"(L)" : (char *)"on left hand");
current(rs,cur_ring[RIGHT], "wearing",
terse ? (char *)"(R)" : (char *)"on right hand");
when '@':
stat_msg = TRUE;
status(rs);
stat_msg = FALSE;
after = FALSE;
otherwise:
after = FALSE;
#ifdef MASTER
if (wizard) switch (ch)
{
case '|': msg(rs,"@ %d,%d", hero.y, hero.x);
when 'C': create_obj();
when '$': msg(rs,"inpack = %d", inpack);
when CTRL('G'): inventory(rs,lvl_obj, 0);
when CTRL('W'): whatis(rs,FALSE, 0);
when CTRL('D'): level++; new_level();
when CTRL('A'): level--; new_level();
when CTRL('F'): show_map();
when CTRL('T'): teleport();
when CTRL('E'): msg(rs,"food left: %d", food_left);
when CTRL('C'): add_pass();
when CTRL('X'): turn_see(on(player, SEEMONST));
when CTRL('~'):
{
THING *item;
if ((item = get_item(rs,"charge", STICK)) != NULL)
item->o_charges = 10000;
}
when CTRL('I'):
{
int i;
THING *obj;
for (i = 0; i < 9; i++)
raise_level(rs);
/*
* Give him a sword (+1,+1)
*/
obj = new_item();
init_weapon(obj, TWOSWORD);
obj->o_hplus = 1;
obj->o_dplus = 1;
add_pack(rs,obj, TRUE);
cur_weapon = obj;
/*
* And his suit of armor
*/
obj = new_item();
obj->o_type = ARMOR;
obj->o_which = PLATE_MAIL;
obj->o_arm = -5;
obj->o_flags |= ISKNOW;
obj->o_count = 1;
obj->o_group = 0;
cur_armor = obj;
add_pack(rs,obj, TRUE);
}
when '*' :
pr_list();
otherwise:
illcom(rs,ch);
}
else
#endif
illcom(rs,ch);
}
/*
* turn off flags if no longer needed
*/
if (!running)
door_stop = FALSE;
}
/*
* If he ran into something to take, let him pick it up.
*/
if (take != 0)
pick_up(rs,take);
if (!running)
door_stop = FALSE;
if (!after)
ntimes++;
}
do_daemons(rs,AFTER);
do_fuses(rs,AFTER);
if (ISRING(LEFT, R_SEARCH))
search(rs);
else if (ISRING(LEFT, R_TELEPORT) && rnd(50) == 0)
teleport(rs);
if (ISRING(RIGHT, R_SEARCH))
search(rs);
else if (ISRING(RIGHT, R_TELEPORT) && rnd(50) == 0)
teleport(rs);
}
/*
* illcom:
* What to do with an illegal command
*/
void
illcom(struct rogue_state *rs,int ch)
{
save_msg = FALSE;
count = 0;
msg(rs,"illegal command '%s'", unctrl(ch));
save_msg = TRUE;
}
/*
* search:
* player gropes about him to find hidden things.
*/
void
search(struct rogue_state *rs)
{
register int y, x;
register char *fp;
register int ey, ex;
int probinc;
bool found;
ey = hero.y + 1;
ex = hero.x + 1;
probinc = (on(player, ISHALU) ? 3 : 0);
probinc += (on(player, ISBLIND) ? 2 : 0);
found = FALSE;
for (y = hero.y - 1; y <= ey; y++)
for (x = hero.x - 1; x <= ex; x++)
{
if (y == hero.y && x == hero.x)
continue;
fp = &flat(y, x);
if (!(*fp & F_REAL))
switch (chat(y, x))
{
case '|':
case '-':
if (rnd(5 + probinc) != 0)
break;
chat(y, x) = DOOR;
msg(rs,"a secret door");
foundone:
found = TRUE;
*fp |= F_REAL;
count = FALSE;
running = FALSE;
break;
case FLOOR:
if (rnd(2 + probinc) != 0)
break;
chat(y, x) = TRAP;
if (!terse)
addmsg(rs,"you found ");
if (on(player, ISHALU))
msg(rs,(char *)tr_name[rnd(NTRAPS)]);
else {
msg(rs,(char *)tr_name[*fp & F_TMASK]);
*fp |= F_SEEN;
}
goto foundone;
break;
case ' ':
if (rnd(3 + probinc) != 0)
break;
chat(y, x) = PASSAGE;
goto foundone;
}
}
if (found)
look(rs,FALSE);
}
/*
* help:
* Give single character help, or the whole mess if he wants it
*/
void
help(struct rogue_state *rs)
{
register const struct h_list *strp;
register char helpch;
register int numprint, cnt;
msg(rs,"character you want help for (* for all): ");
helpch = readchar(rs);
mpos = 0;
/*
* If its not a *, print the right help string
* or an error if he typed a funny character.
*/
if (helpch != '*')
{
move(0, 0);
for (strp = helpstr; strp->h_desc != NULL; strp++)
if (strp->h_ch == helpch)
{
lower_msg = TRUE;
msg(rs,"%s%s", unctrl(strp->h_ch), strp->h_desc);
lower_msg = FALSE;
return;
}
msg(rs,"unknown character '%s'", unctrl(helpch));
return;
}
/*
* Here we print help for everything.
* Then wait before we return to command mode
*/
numprint = 0;
for (strp = helpstr; strp->h_desc != NULL; strp++)
if (strp->h_print)
numprint++;
if (numprint & 01) /* round odd numbers up */
numprint++;
numprint /= 2;
if (numprint > LINES - 1)
numprint = LINES - 1;
wclear(hw);
cnt = 0;
for (strp = helpstr; strp->h_desc != NULL; strp++)
if (strp->h_print)
{
wmove(hw, cnt % numprint, cnt >= numprint ? COLS / 2 : 0);
if (strp->h_ch)
waddstr(hw, unctrl(strp->h_ch));
waddstr(hw, strp->h_desc);
if (++cnt >= numprint * 2)
break;
}
wmove(hw, LINES - 1, 0);
waddstr(hw, "--Press space to continue--");
wrefresh(hw);
wait_for(rs,' ');
clearok(stdscr, TRUE);
/*
refresh();
*/
msg(rs,"");
touchwin(stdscr);
wrefresh(stdscr);
}
/*
* identify:
* Tell the player what a certain thing is.
*/
void
identify(struct rogue_state *rs)
{
register int ch;
register const struct h_list *hp;
register char *str;
static const struct h_list ident_list[] = {
{'|', "wall of a room", FALSE},
{'-', "wall of a room", FALSE},
{GOLD, "gold", FALSE},
{STAIRS, "a staircase", FALSE},
{DOOR, "door", FALSE},
{FLOOR, "room floor", FALSE},
{PLAYER, "you", FALSE},
{PASSAGE, "passage", FALSE},
{TRAP, "trap", FALSE},
{POTION, "potion", FALSE},
{SCROLL, "scroll", FALSE},
{FOOD, "food", FALSE},
{WEAPON, "weapon", FALSE},
{' ', "solid rock", FALSE},
{ARMOR, "armor", FALSE},
{AMULET, "the Amulet of Yendor", FALSE},
{RING, "ring", FALSE},
{STICK, "wand or staff", FALSE},
{'\0'}
};
msg(rs,"what do you want identified? ");
ch = readchar(rs);
mpos = 0;
if (ch == ESCAPE)
{
msg(rs,"");
return;
}
if (isupper(ch))
str = monsters[ch-'A'].m_name;
else
{
str = "unknown character";
for (hp = ident_list; hp->h_ch != '\0'; hp++)
if (hp->h_ch == ch)
{
str = hp->h_desc;
break;
}
}
msg(rs,"'%s': %s", unctrl(ch), str);
}
/*
* d_level:
* He wants to go down a level
*/
void
d_level(struct rogue_state *rs)
{
if (levit_check(rs))
return;
if (chat(hero.y, hero.x) != STAIRS)
msg(rs,"I see no way down");
else
{
level++;
seenstairs = FALSE;
new_level(rs);
}
}
/*
* u_level:
* He wants to go up a level
*/
void
u_level(struct rogue_state *rs)
{
if (levit_check(rs))
return;
if (chat(hero.y, hero.x) == STAIRS)
if (amulet)
{
level--;
if (level == 0)
total_winner(rs);
new_level(rs);
msg(rs,"you feel a wrenching sensation in your gut");
}
else
msg(rs,"your way is magically blocked");
else
msg(rs,"I see no way up");
}
/*
* levit_check:
* Check to see if she's levitating, and if she is, print an
* appropriate message.
*/
bool
levit_check(struct rogue_state *rs)
{
if (!on(player, ISLEVIT))
return FALSE;
msg(rs,"You can't. You're floating off the ground!");
return TRUE;
}
/*
* call:
* Allow a user to call a potion, scroll, or ring something
*/
void
call(struct rogue_state *rs)
{
register THING *obj;
register const struct obj_info *op = NULL;
register char **guess; const char *elsewise = NULL;
register const bool *know;
obj = get_item(rs,"call", CALLABLE);
/*
* Make certain that it is somethings that we want to wear
*/
if (obj == NULL)
return;
switch (obj->o_type)
{
case RING:
op = &ring_info[obj->o_which];
elsewise = r_stones[obj->o_which];
goto norm;
when POTION:
op = &pot_info[obj->o_which];
elsewise = p_colors[obj->o_which];
goto norm;
when SCROLL:
op = &scr_info[obj->o_which];
elsewise = s_names[obj->o_which];
goto norm;
when STICK:
op = &ws_info[obj->o_which];
elsewise = ws_made[obj->o_which];
norm:
know = &op->oi_know;
guess = (char **)&op->oi_guess;
if (*guess != NULL)
elsewise = *guess;
when FOOD:
msg(rs,"you can't call that anything");
return;
otherwise:
guess = &obj->o_label;
know = NULL;
elsewise = obj->o_label;
}
if (know != NULL && *know)
{
msg(rs,"that has already been identified");
return;
}
if (elsewise != NULL && elsewise == *guess)
{
if (!terse)
addmsg(rs,"Was ");
msg(rs,"called \"%s\"", elsewise);
}
if (terse)
msg(rs,"call it: ");
else
msg(rs,"what do you want to call it? ");
if (elsewise == NULL)
strcpy(prbuf, "");
else
strcpy(prbuf, elsewise);
if (get_str(rs,prbuf, stdscr) == NORM)
{
if (*guess != NULL)
free(*guess);
*guess = (char *)malloc((unsigned int) strlen(prbuf) + 1);
strcpy(*guess, prbuf);
}
}
/*
* current:
* Print the current weapon/armor
*/
void
current(struct rogue_state *rs,THING *cur, char *how, char *where)
{
after = FALSE;
if (cur != NULL)
{
if (!terse)
addmsg(rs,"you are %s (", how);
inv_describe = FALSE;
addmsg(rs,"%c) %s", cur->o_packch, inv_name(cur, TRUE));
inv_describe = TRUE;
if (where)
addmsg(rs," %s", where);
endmsg(rs);
}
else
{
if (!terse)
addmsg(rs,"you are ");
addmsg(rs,"%s nothing", how);
if (where)
addmsg(rs," %s", where);
endmsg(rs);
}
}

1500
src/cc/rogue/config.guess vendored Executable file

File diff suppressed because it is too large Load Diff

270
src/cc/rogue/config.h Normal file
View File

@@ -0,0 +1,270 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if scorefile is top scores, not top players */
#define ALLSCORES 1
/* Define if checktime feature should be enabled */
/* #undef CHECKTIME */
/* Define to group owner of setgid executable */
/* #undef GROUPOWNER */
/* Define to 1 if you have the `alarm' function. */
#define HAVE_ALARM 1
/* Define to 1 if you have the <arpa/inet.h> header file. */
#define HAVE_ARPA_INET_H 1
/* Define to 1 if libcurses is requested */
#define HAVE_CURSES_H 1
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
/* #undef HAVE_DOPRNT */
/* Define to 1 if you have the `erasechar' function. */
#define HAVE_ERASECHAR 1
/* Define if ncurses has ESCDELAY variable */
#define HAVE_ESCDELAY 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define to 1 if you have the `fork' function. */
#define HAVE_FORK 1
/* Define to 1 if you have the `getgid' function. */
#define HAVE_GETGID 1
/* Define to 1 if you have the `getloadavg' function. */
#define HAVE_GETLOADAVG 1
/* Define to 1 if you have the `getpass' function. */
#define HAVE_GETPASS 1
/* Define to 1 if you have the `getpwuid' function. */
#define HAVE_GETPWUID 1
/* Define to 1 if you have the `getuid' function. */
#define HAVE_GETUID 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `killchar' function. */
#define HAVE_KILLCHAR 1
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the `loadav' function. */
/* #undef HAVE_LOADAV */
/* Define to 1 if `lstat' has the bug that it succeeds when given the
zero-length file name argument. */
/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1
/* Define to 1 if libncurses is requested */
/* #undef HAVE_NCURSES_H */
/* Define to 1 if you have the <ncurses/term.h> header file. */
/* #undef HAVE_NCURSES_TERM_H */
/* Define to 1 if you have the `nlist' function. */
/* #undef HAVE_NLIST */
/* Define to 1 if you have the <nlist.h> header file. */
#define HAVE_NLIST_H 1
/* Define to 1 if you have the <process.h> header file. */
/* #undef HAVE_PROCESS_H */
/* Define to 1 if you have the <pwd.h> header file. */
#define HAVE_PWD_H 1
/* Define to 1 if you have the `setenv' function. */
#define HAVE_SETENV 1
/* Define to 1 if you have the `setgid' function. */
#define HAVE_SETGID 1
/* Define to 1 if you have the `setregid' function. */
#define HAVE_SETREGID 1
/* Define to 1 if you have the `setresgid' function. */
/* #undef HAVE_SETRESGID */
/* Define to 1 if you have the `setresuid' function. */
/* #undef HAVE_SETRESUID */
/* Define to 1 if you have the `setreuid' function. */
#define HAVE_SETREUID 1
/* Define to 1 if you have the `setuid' function. */
#define HAVE_SETUID 1
/* Define to 1 if you have the `spawnl' function. */
/* #undef HAVE_SPAWNL */
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
/* #undef HAVE_STAT_EMPTY_STRING_BUG */
/* Define to 1 if stdbool.h conforms to C99. */
#define HAVE_STDBOOL_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/utsname.h> header file. */
#define HAVE_SYS_UTSNAME_H 1
/* Define to 1 if you have the <termios.h> header file. */
#define HAVE_TERMIOS_H 1
/* Define to 1 if you have the <term.h> header file. */
#define HAVE_TERM_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the <utmp.h> header file. */
#define HAVE_UTMP_H 1
/* Define to 1 if you have the `vfork' function. */
#define HAVE_VFORK 1
/* Define to 1 if you have the <vfork.h> header file. */
/* #undef HAVE_VFORK_H */
/* Define to 1 if you have the `vprintf' function. */
#define HAVE_VPRINTF 1
/* Define to 1 if `fork' works. */
#define HAVE_WORKING_FORK 1
/* Define to 1 if `vfork' works. */
#define HAVE_WORKING_VFORK 1
/* Define to 1 if the system has the type `_Bool'. */
#define HAVE__BOOL 1
/* Define to 1 if you have the `_spawnl' function. */
/* #undef HAVE__SPAWNL */
/* define if we should use program's load average function instead of system
*/
/* #undef LOADAV */
/* Define to file to use for scoreboard lockfile */
#define LOCKFILE "rogue.lck"
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */
/* Define to include wizard mode */
/* #undef MASTER */
/* Define if maxusers feature should be enabled */
/* #undef MAXLOAD */
/* Define if maxusers feature should be enabled */
/* #undef MAXUSERS */
/* kernel file to pass to nlist() when reading load average (unlikely to work)
*/
/* #undef NAMELIST */
/* word for the number of scores to store in scoreboard */
#define NUMNAME "Ten"
/* number of scores to store in scoreboard */
#define NUMSCORES 10
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "yendor@rogueforge.net"
/* Define to the full name of this package. */
#define PACKAGE_NAME "Rogue"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "Rogue 5.4.4"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "rogue"
/* Define to the version of this package. */
#define PACKAGE_VERSION "5.4.4"
/* Define crypt(3) wizard mode password */
/* #undef PASSWD */
/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void
/* Define to file to use for scoreboard */
#define SCOREFILE "rogue.scr"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
/* #undef TM_IN_SYS_TIME */
/* define if we should use program's user counting function instead of
system's */
/* #undef UCOUNT */
/* utmp like file to pass to ucount() when counting online users (unlikely to
work) */
/* #undef UTMP */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef gid_t */
/* Define to `int' if <sys/types.h> does not define. */
/* #undef pid_t */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define to `int' if <sys/types.h> doesn't define. */
/* #undef uid_t */
/* Define as `fork' if `vfork' does not work. */
/* #undef vfork */

269
src/cc/rogue/config.h.in Normal file
View File

@@ -0,0 +1,269 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if scorefile is top scores, not top players */
#undef ALLSCORES
/* Define if checktime feature should be enabled */
#undef CHECKTIME
/* Define to group owner of setgid executable */
#undef GROUPOWNER
/* Define to 1 if you have the `alarm' function. */
#undef HAVE_ALARM
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
/* Define to 1 if libcurses is requested */
#undef HAVE_CURSES_H
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
#undef HAVE_DOPRNT
/* Define to 1 if you have the `erasechar' function. */
#undef HAVE_ERASECHAR
/* Define if ncurses has ESCDELAY variable */
#undef HAVE_ESCDELAY
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
/* Define to 1 if you have the `getgid' function. */
#undef HAVE_GETGID
/* Define to 1 if you have the `getloadavg' function. */
#undef HAVE_GETLOADAVG
/* Define to 1 if you have the `getpass' function. */
#undef HAVE_GETPASS
/* Define to 1 if you have the `getpwuid' function. */
#undef HAVE_GETPWUID
/* Define to 1 if you have the `getuid' function. */
#undef HAVE_GETUID
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define to 1 if you have the `killchar' function. */
#undef HAVE_KILLCHAR
/* Define to 1 if you have the <limits.h> header file. */
#undef HAVE_LIMITS_H
/* Define to 1 if you have the `loadav' function. */
#undef HAVE_LOADAV
/* Define to 1 if `lstat' has the bug that it succeeds when given the
zero-length file name argument. */
#undef HAVE_LSTAT_EMPTY_STRING_BUG
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */
#undef HAVE_MEMSET
/* Define to 1 if libncurses is requested */
#undef HAVE_NCURSES_H
/* Define to 1 if you have the <ncurses/term.h> header file. */
#undef HAVE_NCURSES_TERM_H
/* Define to 1 if you have the `nlist' function. */
#undef HAVE_NLIST
/* Define to 1 if you have the <nlist.h> header file. */
#undef HAVE_NLIST_H
/* Define to 1 if you have the <process.h> header file. */
#undef HAVE_PROCESS_H
/* Define to 1 if you have the <pwd.h> header file. */
#undef HAVE_PWD_H
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
/* Define to 1 if you have the `setgid' function. */
#undef HAVE_SETGID
/* Define to 1 if you have the `setregid' function. */
#undef HAVE_SETREGID
/* Define to 1 if you have the `setresgid' function. */
#undef HAVE_SETRESGID
/* Define to 1 if you have the `setresuid' function. */
#undef HAVE_SETRESUID
/* Define to 1 if you have the `setreuid' function. */
#undef HAVE_SETREUID
/* Define to 1 if you have the `setuid' function. */
#undef HAVE_SETUID
/* Define to 1 if you have the `spawnl' function. */
#undef HAVE_SPAWNL
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
#undef HAVE_STAT_EMPTY_STRING_BUG
/* Define to 1 if stdbool.h conforms to C99. */
#undef HAVE_STDBOOL_H
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define to 1 if you have the `strchr' function. */
#undef HAVE_STRCHR
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to 1 if you have the <sys/utsname.h> header file. */
#undef HAVE_SYS_UTSNAME_H
/* Define to 1 if you have the <termios.h> header file. */
#undef HAVE_TERMIOS_H
/* Define to 1 if you have the <term.h> header file. */
#undef HAVE_TERM_H
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define to 1 if you have the <utmp.h> header file. */
#undef HAVE_UTMP_H
/* Define to 1 if you have the `vfork' function. */
#undef HAVE_VFORK
/* Define to 1 if you have the <vfork.h> header file. */
#undef HAVE_VFORK_H
/* Define to 1 if you have the `vprintf' function. */
#undef HAVE_VPRINTF
/* Define to 1 if `fork' works. */
#undef HAVE_WORKING_FORK
/* Define to 1 if `vfork' works. */
#undef HAVE_WORKING_VFORK
/* Define to 1 if the system has the type `_Bool'. */
#undef HAVE__BOOL
/* Define to 1 if you have the `_spawnl' function. */
#undef HAVE__SPAWNL
/* define if we should use program's load average function instead of system
*/
#undef LOADAV
/* Define to file to use for scoreboard lockfile */
#undef LOCKFILE
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
#undef LSTAT_FOLLOWS_SLASHED_SYMLINK
/* Define to include wizard mode */
#undef MASTER
/* Define if maxusers feature should be enabled */
#undef MAXLOAD
/* Define if maxusers feature should be enabled */
#undef MAXUSERS
/* kernel file to pass to nlist() when reading load average (unlikely to work)
*/
#undef NAMELIST
/* word for the number of scores to store in scoreboard */
#undef NUMNAME
/* number of scores to store in scoreboard */
#undef NUMSCORES
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define crypt(3) wizard mode password */
#undef PASSWD
/* Define as the return type of signal handlers (`int' or `void'). */
#undef RETSIGTYPE
/* Define to file to use for scoreboard */
#undef SCOREFILE
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if your <sys/time.h> declares `struct tm'. */
#undef TM_IN_SYS_TIME
/* define if we should use program's user counting function instead of
system's */
#undef UCOUNT
/* utmp like file to pass to ucount() when counting online users (unlikely to
work) */
#undef UTMP
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `int' if <sys/types.h> doesn't define. */
#undef gid_t
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
/* Define to `unsigned int' if <sys/types.h> does not define. */
#undef size_t
/* Define to `int' if <sys/types.h> doesn't define. */
#undef uid_t
/* Define as `fork' if `vfork' does not work. */
#undef vfork

1608
src/cc/rogue/config.sub vendored Executable file

File diff suppressed because it is too large Load Diff

7511
src/cc/rogue/configure vendored Executable file

File diff suppressed because it is too large Load Diff

246
src/cc/rogue/configure.ac Normal file
View File

@@ -0,0 +1,246 @@
# -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.
AC_PREREQ(2.56)
AC_INIT([Rogue],[5.4.4], [yendor@rogueforge.net])
AC_CONFIG_SRCDIR([armor.c])
AC_CONFIG_HEADER([config.h])
AC_CONFIG_FILES([Makefile rogue.6 rogue.cat rogue.doc rogue.html rogue.me])
AC_CANONICAL_SYSTEM([])
# Checks for programs.
AC_PROG_CC
# Checks for libraries.
# Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS([arpa/inet.h sys/utsname.h pwd.h fcntl.h limits.h nlist.h stdlib.h string.h sys/ioctl.h termios.h unistd.h utmp.h term.h ncurses/term.h process.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
AC_C_CONST
AC_TYPE_UID_T
AC_TYPE_SIZE_T
AC_STRUCT_TM
MP_WITH_CURSES
# Checks for library functions.
AC_FUNC_FORK
AC_PROG_GCC_TRADITIONAL
AC_FUNC_LSTAT
AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK
AC_TYPE_SIGNAL
AC_FUNC_STAT
AC_FUNC_VPRINTF
AC_CHECK_FUNCS([erasechar killchar alarm getpass memset setenv strchr nlist _spawnl spawnl getpwuid loadav getloadavg strerror setresgid setregid setgid setresuid setreuid setuid getuid getgid])
AC_CHECK_PROG([NROFF], [nroff], [nroff],)
AC_CHECK_PROG([GROFF], [groff], [groff],)
AC_CHECK_PROG([COLCRT], [colcrt], [colcrt],)
AC_CHECK_PROG([TBL], [tbl], [tbl],)
AC_CHECK_PROG([SED], [sed], [sed],)
AC_ARG_WITH(program-name, AC_HELP_STRING([--with-program-name=NAME],[alternate executable name]),[progname="$withval" ], [progname="rogue"] )
PROGRAM=$progname
AC_SUBST(PROGRAM)
AC_ARG_ENABLE(setgid, AC_HELP_STRING([--enable-setgid=NAME],[install executable as setgid with group ownership of NAME @<:@default=no@:>@])],[],[])
AC_MSG_CHECKING([if using setgid execute bit])
if test "x$enable_setgid" = "xno" ; then
GROUPOWNER=
elif test "x$enable_setgid" = "xyes" ; then
GROUPOWNER=games
elif test "x$enable_setgid" = "x" ; then
GROUPOWNER=
else
GROUPOWNER=$enable_setgid
fi
if test "x$GROUPOWNER" != "x" ; then
AC_DEFINE_UNQUOTED([GROUPOWNER],[$GROUPOWNER], [Define to group owner of setgid executable])
AC_MSG_RESULT([$GROUPOWNER])
else
AC_MSG_RESULT([no])
fi
AC_SUBST(GROUPOWNER)
AC_ARG_ENABLE([scorefile],[AC_HELP_STRING([--enable-scorefile=SCOREFILE], [enable scoreboard with given filename])],[],[])
AC_MSG_CHECKING([for scoreboard file])
if test "x$enable_scorefile" = "xno" ; then
SCOREFILE=
elif test "x$enable_scorefile" = "xyes" ; then
SCOREFILE=$progname.scr
elif test "x$enable_scorefile" = "x" ; then
SCOREFILE=$progname.scr
else
SCOREFILE=$enable_scorefile
fi
if test "x$SCOREFILE" != "x" ; then
AC_DEFINE_UNQUOTED([SCOREFILE], ["$SCOREFILE"], [Define to file to use for scoreboard])
AC_MSG_RESULT([$SCOREFILE])
else
AC_MSG_RESULT([disabled])
fi
AC_SUBST(SCOREFILE)
AC_ARG_ENABLE([lockfile],[AC_HELP_STRING([--enable-lockfile=LOCKFILE], [enable scoreboard lockfile with given filename])],[],[])
AC_MSG_CHECKING([for scoreboard lockfile file])
if test "x$enable_lockfile" = "xno" ; then
LOCKFILE=
elif test "x$enable_lockfile" = "xyes" ; then
LOCKFILE=$progname.lck
elif test "x$enable_lockfile" = "x" ; then
LOCKFILE=$progname.lck
else
LOCKFILE=$enable_lockfile
fi
if test "x$LOCKFILE" != "x" ; then
AC_DEFINE_UNQUOTED([LOCKFILE], ["$LOCKFILE"], [Define to file to use for scoreboard lockfile])
AC_MSG_RESULT([$LOCKFILE])
else
AC_MSG_RESULT([disabled])
fi
AC_SUBST(LOCKFILE)
AC_ARG_ENABLE([wizardmode],[AC_HELP_STRING([--enable-wizardmode], [enable availability of wizard mode @<:@default=no@:>@])],[],[])
AC_MSG_CHECKING([if wizard mode is enabled])
if test "x$enable_wizardmode" = "xno" ; then
AC_MSG_RESULT([no])
elif test "x$enable_wizardmode" = "x" ; then
AC_MSG_RESULT([no])
else
AC_DEFINE([MASTER], [], [Define to include wizard mode])
if test "x$enable_wizardmode" != "xyes" ; then
AC_DEFINE_UNQUOTED([PASSWD],[$enable_wizardmode], [Define crypt(3) wizard mode password])
fi
AC_MSG_RESULT([yes])
fi
AC_ARG_ENABLE([allscores],[AC_HELP_STRING([--enable-allscores], [enable scoreboard to show top scores, not just top players @<:@default=yes@:>@])],[],[enable_allscores=yes])
AC_MSG_CHECKING([if allscores is enabled])
if test "x$enable_allscores" = "xyes" ; then
AC_DEFINE([ALLSCORES], [1], [Define if scorefile is top scores, not top players])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
AC_ARG_ENABLE([checktime],[AC_HELP_STRING([--enable-checktime], [enable checktime @<:@default=no@:>@])],[],[])
AC_MSG_CHECKING([if checktime is enabled])
if test "x$enable_checktime" = "xyes" ; then
AC_DEFINE([CHECKTIME], [1], [Define if checktime feature should be enabled])
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
fi
AC_ARG_ENABLE([maxload],[AC_HELP_STRING([--enable-maxload], [enable maxload @<:@default=no@:>@])],[],[])
AC_MSG_CHECKING([runtime execution limit (maximum system load average)])
if test "x$enable_maxload" = "xyes" ; then
AC_DEFINE([MAXLOAD], [100], [Define if maxload feature should be enabled])
AC_MSG_RESULT([100])
elif test "x$enable_maxload" = "x" ; then
AC_MSG_RESULT([unlimited])
elif test "x$enable_maxload" = "xno" ; then
AC_MSG_RESULT([unlimited])
else
AC_DEFINE_UNQUOTED([MAXLOAD], [$enable_maxload], [Define if maxload feature should be enabled])
AC_MSG_RESULT([$enable_maxload])
fi
AC_ARG_ENABLE([maxusers],[AC_HELP_STRING([--enable-maxusers], [enable maxuser @<:@default=no@:>@])],[],[])
AC_MSG_CHECKING([runtime execution limit (maximum online system users)])
if test "x$enable_maxusers" = "xyes" ; then
AC_DEFINE([MAXUSERS], [100], [Define if maxusers feature should be enabled])
AC_MSG_RESULT([100])
elif test "x$enable_maxusers" = "x" ; then
AC_MSG_RESULT([unlimited])
elif test "x$enable_maxload" = "xno" ; then
AC_MSG_RESULT([unlimited])
else
AC_DEFINE_UNQUOTED([MAXLOAD], [$enable_maxusers], [Define if maxusers feature should be enabled])
AC_MSG_RESULT([$enable_maxusers])
fi
AC_ARG_ENABLE([numscores],[AC_HELP_STRING([--enable-numscores], [number of scores to store in scoreboard @<:@default=10@:>@])],[],[])
AC_MSG_CHECKING([what the number of scores to store in scoreboard is])
if test "x$numscores" = "xyes" ; then
AC_DEFINE([NUMSCORES], [10], [number of scores to store in scoreboard])
AC_MSG_RESULT([10])
elif test "x$enable_numscores" = "x" ; then
AC_DEFINE([NUMSCORES], [10], [number of scores to store in scoreboard])
AC_MSG_RESULT([10])
elif test "x$enable_numscores" = "xno" ; then
AC_DEFINE([NUMSCORES], [10], [number of scores to store in scoreboard])
AC_MSG_RESULT([10])
else
AC_DEFINE_UNQUOTED([NUMSCORES], [$enable_numscores], [number of scores to store in scoreboard])
AC_MSG_RESULT([$enable_numscores])
fi
AC_ARG_ENABLE([numname],[AC_HELP_STRING([--enable-numname], [word for number of scores to store in scoreboard @<:@default=Ten@:>@])],[],[])
AC_MSG_CHECKING([word for the number of scores to store in scoreboard is])
if test "x$enable_numname" = "xyes" ; then
AC_DEFINE([NUMNAME], ["Ten"], [word for the number of scores to store in scoreboard])
AC_MSG_RESULT([Ten])
elif test "x$enable_numname" = "x" ; then
AC_DEFINE([NUMNAME], ["Ten"], [word for the number of scores to store in scoreboard])
AC_MSG_RESULT([Ten])
elif test "x$enable_numname" = "xno" ; then
AC_DEFINE([NUMNAME], ["Ten"], [word for the number of scores to store in scoreboard])
AC_MSG_RESULT([Ten])
else
AC_DEFINE_UNQUOTED([NUMNAME], ["$enable_numname"], [word for the number of scores to store in scoreboard])
AC_MSG_RESULT([$enable_numname])
fi
AC_ARG_ENABLE([loadav],[AC_HELP_STRING([--enable-loadav=NAMELIST], [use program's load average function (unlikely to work) @<:@default=no@:>@])],[],[])
AC_MSG_CHECKING([whether to use program's built in load average function])
if test "x$enable_loadav" = "xyes" ; then
AC_DEFINE([LOADAV], [], [define if we should use program's load average function instead of system])
AC_DEFINE([NAMELIST], [/vmunix], [kernel file to pass to nlist() when reading load average (unlikely to work)])
AC_MSG_RESULT([/vmunix])
elif test "x$enable_loadav" = "x" ; then
AC_MSG_RESULT([no])
elif test "x$enable_loadav" = "xno" ; then
AC_MSG_RESULT([no])
else
AC_DEFINE([LOADAV], [], [define if we should use program's load average function instead of system])
AC_DEFINE_UNQUOTED([NAMELIST], [$enable_loadav], [kernel file to pass to nlist() when reading load average (unlikely to work)])
AC_MSG_RESULT([$enable_loadav])
fi
AC_ARG_ENABLE([ucount],[AC_HELP_STRING([--enable-ucount=UTMPFILE], [use program's own function to count users (unlikely to work) @<:@default=no@:>@])],[],[])
AC_MSG_CHECKING([whether to use program's built in user counting function])
if test "x$enable_ucount" = "xyes" ; then
AC_DEFINE([UCOUNT], [], [define if we should use program's user counting function instead of system's])
AC_DEFINE([UTMP], [/etc/utmp], [utmp like file to pass to ucount() when counting online users (unlikely to work)])
AC_MSG_RESULT([/etc/utmp])
elif test "x$enable_ucount" = "x" ; then
AC_MSG_RESULT([no])
elif test "x$enable_count" = "xno" ; then
AC_MSG_RESULT([no])
else
AC_DEFINE([UCOUNT], [], [define if we should use program's user counting function instead of system's])
AC_DEFINE_UNQUOTED([UTMP], [$enable_ucount], [utmp like file to pass to ucount() when counting online users (unlikely to work)])
AC_MSG_RESULT([$enable_ucount])
fi
TARGET=$target
AC_SUBST(TARGET)
AC_MSG_CHECKING([whether to docdir is defined])
if test "x$docdir" = "x" ; then
AC_MSG_RESULT([docdir undefined])
docdir=\${datadir}/doc/\${PACKAGE_TARNAME}
AC_SUBST(docdir)
else
AC_MSG_RESULT([docdir defined])
fi
AC_OUTPUT

108
src/cc/rogue/cursesd.c Normal file
View File

@@ -0,0 +1,108 @@
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#include "cursesd.h"
static int32_t endwinflag;
WINDOW *initscr()
{
if ( stdscr == 0 )
stdscr = (WINDOW *)calloc(1,sizeof(*stdscr));
return(stdscr);
}
void endwin()
{
if ( stdscr != 0 )
free(stdscr), stdscr = 0;
endwinflag = 1;
}
int isendwin(void)
{
return(endwinflag);
}
int wrefresh(WINDOW *win)
{
return(0);
}
int refresh(void)
{
endwinflag = 0;
return(wrefresh(stdscr));
}
int wnoutrefresh(WINDOW *win)
{
return(0);
}
int doupdate(void)
{
return(0);
}
int redrawwin(WINDOW *win)
{
return(wrefresh(win));
}
int wredrawln(WINDOW *win, int beg_line, int num_lines)
{
return(wrefresh(win));
}
int werase(WINDOW *win)
{
}
int erase(void)
{
return(werase(stdscr));
}
int wclear(WINDOW *win)
{
}
int clear(void)
{
return(wclear(stdscr));
}
int wclrtobot(WINDOW *win)
{
}
int clrtobot(void)
{
return(wclrtobot(stdscr));
}
int wclrtoeol(WINDOW *win)
{
}
int clrtoeol(void)
{
return(wclrtoeol(stdscr));
}

133
src/cc/rogue/cursesd.h Normal file
View File

@@ -0,0 +1,133 @@
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#ifndef H_CURSESD_H
#define H_CURSESD_H
#define LINES 24
#define COLS 80
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h> /* we need va_list */
#include <stddef.h> /* we want wchar_t */
#include <stdbool.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#ifdef notyet
struct cursesd_info
{
uint8_t screen[LINES][COLS];
} *stdscr;
typedef struct cursesd_info WINDOW;
WINDOW *initscr(void);
int endwin(void);
int isendwin(void);
//SCREEN *newterm(const char *type, FILE *outfd, FILE *infd);
//SCREEN *set_term(SCREEN *new);
//void delscreen(SCREEN* sp);
int refresh(void);
int wrefresh(WINDOW *win);
//int wnoutrefresh(WINDOW *win);
//int doupdate(void);
int redrawwin(WINDOW *win);
int wredrawln(WINDOW *win, int beg_line, int num_lines);
int erase(void);
int werase(WINDOW *win);
int clear(void);
int wclear(WINDOW *win);
int clrtobot(void);
int wclrtobot(WINDOW *win);
int clrtoeol(void);
int wclrtoeol(WINDOW *win);
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define standout()
#define standend()
#define refresh()
#define raw()
#define noecho()
#define flushinp()
#define clear()
#define clrtoeol()
#define addch(a)
#define werase(a)
#define wclear(a)
#define delwin(a)
#define addstr(a)
#define touchwin(a)
#define idlok(a,b)
#define clearok(a,b)
#define keypad(a,b)
#define leaveok(a,b)
#define waddch(a,b)
#define waddstr(a,b)
#define move(a,b)
#define mvwin(a,b,c)
#define wmove(a,b,c)
#define mvaddch(a,b,c)
#define mvaddstr(a,b,c)
#define wgetnstr(a,b,c)
#define getyx(a,b,c)
#define mvcur(a,b,c,d)
#define mvwaddch(a,b,c,d)
#define mvprintw(...)
#define printw(...)
#define wprintw(...)
#define mvwprintw(...)
#define A_CHARTEXT 0xff
#define inch() 0
#define endwin() 1
#define isendwin() 0
#define baudrate() 9600
#define killchar() 3
#define erasechar() 8
#define wclrtoeol(a) 0
#define wrefresh(a) 0
#define unctrl(a) "^x"
#define getmaxx(a) COLS
#define getmaxy(a) LINES
#define mvinch(a,b) '.'
#define mvwinch(a,b,c) 0
#define newwin(a,b,c,d) 0
#define subwin(a,b,c,d,e) 0
#endif

181
src/cc/rogue/daemon.c Normal file
View File

@@ -0,0 +1,181 @@
/*
* Contains functions for dealing with things that happen in the
* future.
*
* @(#)daemon.c 4.7 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <curses.h>
#include "rogue.h"
#define EMPTY 0
#define DAEMON -1
#define MAXDAEMONS 20
#define _X_ { EMPTY }
struct delayed_action d_list[MAXDAEMONS] = {
_X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
_X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_, _X_,
};
/*
* d_slot:
* Find an empty slot in the daemon/fuse list
*/
struct delayed_action *
d_slot()
{
register struct delayed_action *dev;
for (dev = d_list; dev <= &d_list[MAXDAEMONS-1]; dev++)
if (dev->d_type == EMPTY)
return dev;
#ifdef MASTER
debug("Ran out of fuse slots");
#endif
return NULL;
}
/*
* find_slot:
* Find a particular slot in the table
*/
struct delayed_action *
find_slot(void (*func)(struct rogue_state *rs,int))
{
register struct delayed_action *dev;
for (dev = d_list; dev <= &d_list[MAXDAEMONS-1]; dev++)
if (dev->d_type != EMPTY && func == dev->d_func)
return dev;
return NULL;
}
/*
* start_daemon:
* Start a daemon, takes a function.
*/
void
start_daemon(void (*func)(struct rogue_state *rs,int), int arg, int type)
{
register struct delayed_action *dev;
dev = d_slot();
dev->d_type = type;
dev->d_func = func;
dev->d_arg = arg;
dev->d_time = DAEMON;
}
/*
* kill_daemon:
* Remove a daemon from the list
*/
void
kill_daemon(void (*func)(struct rogue_state *rs,int))
{
register struct delayed_action *dev;
if ((dev = find_slot(func)) == NULL)
return;
/*
* Take it out of the list
*/
dev->d_type = EMPTY;
}
/*
* do_daemons:
* Run all the daemons that are active with the current flag,
* passing the argument to the function.
*/
void
do_daemons(struct rogue_state *rs,int flag)
{
register struct delayed_action *dev;
/*
* Loop through the devil list
*/
for (dev = d_list; dev <= &d_list[MAXDAEMONS-1]; dev++)
/*
* Executing each one, giving it the proper arguments
*/
if (dev->d_type == flag && dev->d_time == DAEMON)
(*dev->d_func)(rs,dev->d_arg);
}
/*
* fuse:
* Start a fuse to go off in a certain number of turns
*/
void
fuse(void (*func)(struct rogue_state *rs,int), int arg, int time, int type)
{
register struct delayed_action *wire;
wire = d_slot();
wire->d_type = type;
wire->d_func = func;
wire->d_arg = arg;
wire->d_time = time;
}
/*
* lengthen:
* Increase the time until a fuse goes off
*/
void
lengthen(void (*func)(struct rogue_state *rs,int), int xtime)
{
register struct delayed_action *wire;
if ((wire = find_slot(func)) == NULL)
return;
wire->d_time += xtime;
}
/*
* extinguish:
* Put out a fuse
*/
void
extinguish(void (*func)(struct rogue_state *rs,int))
{
register struct delayed_action *wire;
if ((wire = find_slot(func)) == NULL)
return;
wire->d_type = EMPTY;
}
/*
* do_fuses:
* Decrement counters and start needed fuses
*/
void
do_fuses(struct rogue_state *rs,int flag)
{
register struct delayed_action *wire;
/*
* Step though the list
*/
for (wire = d_list; wire <= &d_list[MAXDAEMONS-1]; wire++)
/*
* Decrementing counters and starting things we want. We also need
* to remove the fuse from the list once it has gone off.
*/
if (flag == wire->d_type && wire->d_time > 0 && --wire->d_time == 0)
{
wire->d_type = EMPTY;
(*wire->d_func)(rs,wire->d_arg);
}
}

294
src/cc/rogue/daemons.c Normal file
View File

@@ -0,0 +1,294 @@
/*
* All the daemon and fuse functions are in here
*
* @(#)daemons.c 4.24 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <curses.h>
#include "rogue.h"
/*
* doctor:
* A healing daemon that restors hit points after rest
*/
void
doctor(struct rogue_state *rs,int arg)
{
register int lv, ohp;
lv = pstats.s_lvl;
ohp = pstats.s_hpt;
quiet++;
if (lv < 8)
{
if (quiet + (lv << 1) > 20)
pstats.s_hpt++;
}
else
if (quiet >= 3)
pstats.s_hpt += rnd(lv - 7) + 1;
if (ISRING(LEFT, R_REGEN))
pstats.s_hpt++;
if (ISRING(RIGHT, R_REGEN))
pstats.s_hpt++;
if (ohp != pstats.s_hpt)
{
if (pstats.s_hpt > max_hp)
pstats.s_hpt = max_hp;
quiet = 0;
}
}
/*
* Swander:
* Called when it is time to start rolling for wandering monsters
*/
void
swander(struct rogue_state *rs,int arg)
{
start_daemon(rollwand, 0, BEFORE);
}
/*
* rollwand:
* Called to roll to see if a wandering monster starts up
*/
int between = 0;
void
rollwand(struct rogue_state *rs,int arg)
{
if (++between >= 4)
{
if (roll(1, 6) == 4)
{
wanderer(rs);
kill_daemon(rollwand);
fuse(swander, 0, WANDERTIME, BEFORE);
}
between = 0;
}
}
/*
* unconfuse:
* Release the poor player from his confusion
*/
void
unconfuse(struct rogue_state *rs,int arg)
{
player.t_flags &= ~ISHUH;
msg(rs,"you feel less %s now", choose_str("trippy", "confused"));
}
/*
* unsee:
* Turn off the ability to see invisible
*/
void
unsee(struct rogue_state *rs,int arg)
{
register THING *th;
for (th = mlist; th != NULL; th = next(th))
if (on(*th, ISINVIS) && see_monst(th))
mvaddch(th->t_pos.y, th->t_pos.x, th->t_oldch);
player.t_flags &= ~CANSEE;
}
/*
* sight:
* He gets his sight back
*/
void
sight(struct rogue_state *rs,int arg)
{
if (on(player, ISBLIND))
{
extinguish(sight);
player.t_flags &= ~ISBLIND;
if (!(proom->r_flags & ISGONE))
enter_room(rs,&hero);
msg(rs,choose_str("far out! Everything is all cosmic again",
"the veil of darkness lifts"));
}
}
/*
* nohaste:
* End the hasting
*/
void
nohaste(struct rogue_state *rs,int arg)
{
player.t_flags &= ~ISHASTE;
msg(rs,"you feel yourself slowing down");
}
/*
* stomach:
* Digest the hero's food
*/
void
stomach(struct rogue_state *rs,int arg)
{
register int oldfood;
int orig_hungry = hungry_state;
if (food_left <= 0)
{
if (food_left-- < -STARVETIME)
death(rs,'s');
/*
* the hero is fainting
*/
if (no_command || rnd(5) != 0)
return;
no_command += rnd(8) + 4;
hungry_state = 3;
if (!terse)
addmsg(rs,choose_str("the munchies overpower your motor capabilities. ",
"you feel too weak from lack of food. "));
msg(rs,choose_str("You freak out", "You faint"));
}
else
{
oldfood = food_left;
food_left -= ring_eat(LEFT) + ring_eat(RIGHT) + 1 - amulet;
if (food_left < MORETIME && oldfood >= MORETIME)
{
hungry_state = 2;
msg(rs,choose_str("the munchies are interfering with your motor capabilites",
"you are starting to feel weak"));
}
else if (food_left < 2 * MORETIME && oldfood >= 2 * MORETIME)
{
hungry_state = 1;
if (terse)
msg(rs,choose_str("getting the munchies", "getting hungry"));
else
msg(rs,choose_str("you are getting the munchies",
"you are starting to get hungry"));
}
}
if (hungry_state != orig_hungry) {
player.t_flags &= ~ISRUN;
running = FALSE;
to_death = FALSE;
count = 0;
}
}
/*
* come_down:
* Take the hero down off her acid trip.
*/
void
come_down(struct rogue_state *rs,int arg)
{
register THING *tp;
register bool seemonst;
if (!on(player, ISHALU))
return;
kill_daemon(visuals);
player.t_flags &= ~ISHALU;
if (on(player, ISBLIND))
return;
/*
* undo the things
*/
for (tp = lvl_obj; tp != NULL; tp = next(tp))
if (cansee(rs,tp->o_pos.y, tp->o_pos.x))
mvaddch(tp->o_pos.y, tp->o_pos.x, tp->o_type);
/*
* undo the monsters
*/
seemonst = on(player, SEEMONST);
for (tp = mlist; tp != NULL; tp = next(tp))
{
move(tp->t_pos.y, tp->t_pos.x);
if (cansee(rs,tp->t_pos.y, tp->t_pos.x))
if (!on(*tp, ISINVIS) || on(player, CANSEE))
addch(tp->t_disguise);
else
addch(chat(tp->t_pos.y, tp->t_pos.x));
else if (seemonst)
{
standout();
addch(tp->t_type);
standend();
}
}
msg(rs,"Everything looks SO boring now.");
}
/*
* visuals:
* change the characters for the player
*/
void
visuals(struct rogue_state *rs,int arg)
{
register THING *tp;
register bool seemonst;
if (!after || (running && jump))
return;
/*
* change the things
*/
for (tp = lvl_obj; tp != NULL; tp = next(tp))
if (cansee(rs,tp->o_pos.y, tp->o_pos.x))
mvaddch(tp->o_pos.y, tp->o_pos.x, rnd_thing());
/*
* change the stairs
*/
if (!seenstairs && cansee(rs,stairs.y, stairs.x))
mvaddch(stairs.y, stairs.x, rnd_thing());
/*
* change the monsters
*/
seemonst = on(player, SEEMONST);
for (tp = mlist; tp != NULL; tp = next(tp))
{
move(tp->t_pos.y, tp->t_pos.x);
if (see_monst(tp))
{
if (tp->t_type == 'X' && tp->t_disguise != 'X')
addch(rnd_thing());
else
addch(rnd(26) + 'A');
}
else if (seemonst)
{
standout();
addch(rnd(26) + 'A');
standend();
}
}
}
/*
* land:
* Land from a levitation potion
*/
void
land(struct rogue_state *rs,int arg)
{
player.t_flags &= ~ISLEVIT;
msg(rs,choose_str("bummer! You've hit the ground",
"you float gently to the ground"));
}

516
src/cc/rogue/extern.c Normal file
View File

@@ -0,0 +1,516 @@
/*
* global variable initializaton
*
* @(#)extern.c 4.82 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <curses.h>
#include "rogue.h"
bool after; /* True if we want after daemons */
bool again; /* Repeating the last command */
int noscore; /* Was a wizard sometime */
bool seenstairs; /* Have seen the stairs (for lsd) */
bool amulet = FALSE; /* He found the amulet */
bool door_stop = FALSE; /* Stop running when we pass a door */
bool fight_flush = FALSE; /* True if toilet input */
bool firstmove = FALSE; /* First move after setting door_stop */
bool got_ltc = FALSE; /* We have gotten the local tty chars */
bool has_hit = FALSE; /* Has a "hit" message pending in msg */
bool in_shell = FALSE; /* True if executing a shell */
bool inv_describe = TRUE; /* Say which way items are being used */
bool jump = FALSE; /* Show running as series of jumps */
bool kamikaze = FALSE; /* to_death really to DEATH */
bool lower_msg = FALSE; /* Messages should start w/lower case */
bool move_on = FALSE; /* Next move shouldn't pick up items */
bool msg_esc = FALSE; /* Check for ESC from msg's --More-- */
bool passgo = FALSE; /* Follow passages */
bool playing = TRUE; /* True until he quits */
bool q_comm = FALSE; /* Are we executing a 'Q' command? */
bool running = FALSE; /* True if player is running */
bool save_msg = TRUE; /* Remember last msg */
bool see_floor = TRUE; /* Show the lamp illuminated floor */
bool stat_msg = FALSE; /* Should status() print as a msg() */
bool terse = FALSE; /* True if we should be short */
bool to_death = FALSE; /* Fighting is to the death! */
bool tombstone = TRUE; /* Print out tombstone at end */
#ifdef MASTER
int wizard = FALSE; /* True if allows wizard commands */
#endif
bool pack_used[26] = { /* Is the character used in the pack? */
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE
};
char dir_ch; /* Direction from last get_dir() call */
char runch; /* Direction player is running */
char take; /* Thing she is taking */
int orig_dsusp; /* Original dsusp char */
char file_name[MAXSTR]; /* Save file name */
char huh[MAXSTR]; /* The last message printed */
char prbuf[2*MAXSTR]; /* buffer for sprintfs */
char whoami[MAXSTR]; /* Name of player */
char fruit[MAXSTR] = /* Favorite fruit */
{ 's', 'l', 'i', 'm', 'e', '-', 'm', 'o', 'l', 'd', '\0' };
char home[MAXSTR] = { '\0' }; /* User's home directory */
char l_last_comm = '\0'; /* Last last_comm */
char l_last_dir = '\0'; /* Last last_dir */
char last_comm = '\0'; /* Last command typed */
char last_dir = '\0'; /* Last direction given */
int n_objs; /* # items listed in inventory() call */
int ntraps; /* Number of traps on this level */
int hungry_state = 0; /* How hungry is he */
int inpack = 0; /* Number of things in pack */
int inv_type = 0; /* Type of inventory to use */
int level = 1; /* What level she is on */
int max_hit; /* Max damage done to her in to_death */
int max_level; /* Deepest player has gone */
int mpos = 0; /* Where cursor is on top line */
int no_food = 0; /* Number of levels without food */
int count = 0; /* Number of times to repeat command */
int food_left; /* Amount of food in hero's stomach */
int lastscore = -1; /* Score before this turn */
int no_command = 0; /* Number of turns asleep */
int no_move = 0; /* Number of turns held in place */
int purse = 0; /* How much gold he has */
int quiet = 0; /* Number of quiet turns */
int vf_hit = 0; /* Number of time flytrap has hit */
//int dnum; /* Dungeon number */
uint64_t seed; /* Random number seed */
coord delta; /* Change indicated to get_dir() */
coord oldpos; /* Position before last look() call */
coord stairs; /* Location of staircase */
PLACE places[MAXLINES*MAXCOLS]; /* level map */
const char *p_colors[MAXPOTIONS]; /* Colors of the potions */
const char *r_stones[MAXRINGS]; /* Stone settings of the rings */
const char *ws_made[MAXSTICKS]; /* What sticks are made of */
const char *ws_type[MAXSTICKS]; /* Is it a wand or a staff */
THING *cur_armor; /* What he is wearing */
THING *cur_ring[2]; /* Which rings are being worn */
THING *cur_weapon; /* Which weapon he is weilding */
THING *l_last_pick = NULL; /* Last last_pick */
THING *last_pick = NULL; /* Last object picked in get_item() */
THING *lvl_obj = NULL; /* List of objects on this level */
THING *mlist = NULL; /* List of monsters on the level */
struct room *oldrp; /* Roomin(&oldpos) */
THING player; /* His stats */
WINDOW *hw = NULL; /* used as a scratch window */
char *s_names[MAXSCROLLS]; /* Names of the scrolls */
FILE *scoreboard = NULL; /* File descriptor for score file */
#define INIT_STATS { 16, 0, 1, 10, 12, "1x4", 12 }
struct stats max_stats = INIT_STATS; /* The maximum for the player */
struct stats orig_max_stats = INIT_STATS;
struct monster monsters[26];
struct room passages[MAXPASS],rooms[MAXROOMS]; /* One for each room -- A level */
struct obj_info things[NUMTHINGS],ring_info[MAXRINGS],pot_info[MAXPOTIONS],arm_info[MAXARMORS],scr_info[MAXSCROLLS],weap_info[MAXWEAPONS + 1],ws_info[MAXSTICKS];
////////////// constants
#define ___ 1
#define XX 10
const struct obj_info origthings[NUMTHINGS] = {
{ 0, 26 }, /* potion */
{ 0, 36 }, /* scroll */
{ 0, 16 }, /* food */
{ 0, 7 }, /* weapon */
{ 0, 7 }, /* armor */
{ 0, 4 }, /* ring */
{ 0, 4 }, /* stick */
};
const struct room origpassages[MAXPASS] = /* One for each passage */
{
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} },
{ {0, 0}, {0, 0}, {0, 0}, 0, ISGONE|ISDARK, 0, {{0,0}} }
};
const struct monster origmonsters[26] =
{
/* Name CARRY FLAG str, exp, lvl, amr, hpt, dmg */
{ "aquator", 0, ISMEAN, { XX, 20, 5, 2, ___, "0x0/0x0" } },
{ "bat", 0, ISFLY, { XX, 1, 1, 3, ___, "1x2" } },
{ "centaur", 15, 0, { XX, 17, 4, 4, ___, "1x2/1x5/1x5" } },
{ "dragon", 100, ISMEAN, { XX,5000, 10, -1, ___, "1x8/1x8/3x10" } },
{ "emu", 0, ISMEAN, { XX, 2, 1, 7, ___, "1x2" } },
{ "venus flytrap", 0, ISMEAN, { XX, 80, 8, 3, ___, "%%%x0" } },
/* NOTE: the damage is %%% so that xstr won't merge this */
/* string with others, since it is written on in the program */
{ "griffin", 20, ISMEAN|ISFLY|ISREGEN, { XX,2000, 13, 2, ___, "4x3/3x5" } },
{ "hobgoblin", 0, ISMEAN, { XX, 3, 1, 5, ___, "1x8" } },
{ "ice monster", 0, 0, { XX, 5, 1, 9, ___, "0x0" } },
{ "jabberwock", 70, 0, { XX,3000, 15, 6, ___, "2x12/2x4" } },
{ "kestrel", 0, ISMEAN|ISFLY, { XX, 1, 1, 7, ___, "1x4" } },
{ "leprechaun", 0, 0, { XX, 10, 3, 8, ___, "1x1" } },
{ "medusa", 40, ISMEAN, { XX,200, 8, 2, ___, "3x4/3x4/2x5" } },
{ "nymph", 100, 0, { XX, 37, 3, 9, ___, "0x0" } },
{ "orc", 15, ISGREED,{ XX, 5, 1, 6, ___, "1x8" } },
{ "phantom", 0, ISINVIS,{ XX,120, 8, 3, ___, "4x4" } },
{ "quagga", 0, ISMEAN, { XX, 15, 3, 3, ___, "1x5/1x5" } },
{ "rattlesnake", 0, ISMEAN, { XX, 9, 2, 3, ___, "1x6" } },
{ "snake", 0, ISMEAN, { XX, 2, 1, 5, ___, "1x3" } },
{ "troll", 50, ISREGEN|ISMEAN,{ XX, 120, 6, 4, ___, "1x8/1x8/2x6" } },
{ "black unicorn", 0, ISMEAN, { XX,190, 7, -2, ___, "1x9/1x9/2x9" } },
{ "vampire", 20, ISREGEN|ISMEAN,{ XX,350, 8, 1, ___, "1x10" } },
{ "wraith", 0, 0, { XX, 55, 5, 4, ___, "1x6" } },
{ "xeroc", 30, 0, { XX,100, 7, 7, ___, "4x4" } },
{ "yeti", 30, 0, { XX, 50, 4, 6, ___, "1x6/1x6" } },
{ "zombie", 0, ISMEAN, { XX, 6, 2, 8, ___, "1x8" } }
};
#undef ___
#undef XX
const struct obj_info origarm_info[MAXARMORS] = {
{ "leather armor", 20, 20, NULL, FALSE },
{ "ring mail", 15, 25, NULL, FALSE },
{ "studded leather armor", 15, 20, NULL, FALSE },
{ "scale mail", 13, 30, NULL, FALSE },
{ "chain mail", 12, 75, NULL, FALSE },
{ "splint mail", 10, 80, NULL, FALSE },
{ "banded mail", 10, 90, NULL, FALSE },
{ "plate mail", 5, 150, NULL, FALSE },
};
const struct obj_info origpot_info[MAXPOTIONS] = {
{ "confusion", 7, 5, NULL, FALSE },
{ "hallucination", 8, 5, NULL, FALSE },
{ "poison", 8, 5, NULL, FALSE },
{ "gain strength", 13, 150, NULL, FALSE },
{ "see invisible", 3, 100, NULL, FALSE },
{ "healing", 13, 130, NULL, FALSE },
{ "monster detection", 6, 130, NULL, FALSE },
{ "magic detection", 6, 105, NULL, FALSE },
{ "raise level", 2, 250, NULL, FALSE },
{ "extra healing", 5, 200, NULL, FALSE },
{ "haste self", 5, 190, NULL, FALSE },
{ "restore strength", 13, 130, NULL, FALSE },
{ "blindness", 5, 5, NULL, FALSE },
{ "levitation", 6, 75, NULL, FALSE },
};
const struct obj_info origring_info[MAXRINGS] = {
{ "protection", 9, 400, NULL, FALSE },
{ "add strength", 9, 400, NULL, FALSE },
{ "sustain strength", 5, 280, NULL, FALSE },
{ "searching", 10, 420, NULL, FALSE },
{ "see invisible", 10, 310, NULL, FALSE },
{ "adornment", 1, 10, NULL, FALSE },
{ "aggravate monster", 10, 10, NULL, FALSE },
{ "dexterity", 8, 440, NULL, FALSE },
{ "increase damage", 8, 400, NULL, FALSE },
{ "regeneration", 4, 460, NULL, FALSE },
{ "slow digestion", 9, 240, NULL, FALSE },
{ "teleportation", 5, 30, NULL, FALSE },
{ "stealth", 7, 470, NULL, FALSE },
{ "maintain armor", 5, 380, NULL, FALSE },
};
const struct obj_info origscr_info[MAXSCROLLS] = {
{ "monster confusion", 7, 140, NULL, FALSE },
{ "magic mapping", 4, 150, NULL, FALSE },
{ "hold monster", 2, 180, NULL, FALSE },
{ "sleep", 3, 5, NULL, FALSE },
{ "enchant armor", 7, 160, NULL, FALSE },
{ "identify potion", 10, 80, NULL, FALSE },
{ "identify scroll", 10, 80, NULL, FALSE },
{ "identify weapon", 6, 80, NULL, FALSE },
{ "identify armor", 7, 100, NULL, FALSE },
{ "identify ring, wand or staff", 10, 115, NULL, FALSE },
{ "scare monster", 3, 200, NULL, FALSE },
{ "food detection", 2, 60, NULL, FALSE },
{ "teleportation", 5, 165, NULL, FALSE },
{ "enchant weapon", 8, 150, NULL, FALSE },
{ "create monster", 4, 75, NULL, FALSE },
{ "remove curse", 7, 105, NULL, FALSE },
{ "aggravate monsters", 3, 20, NULL, FALSE },
{ "protect armor", 2, 250, NULL, FALSE },
};
const struct obj_info origweap_info[MAXWEAPONS + 1] = {
{ "mace", 11, 8, NULL, FALSE },
{ "long sword", 11, 15, NULL, FALSE },
{ "short bow", 12, 15, NULL, FALSE },
{ "arrow", 12, 1, NULL, FALSE },
{ "dagger", 8, 3, NULL, FALSE },
{ "two handed sword", 10, 75, NULL, FALSE },
{ "dart", 12, 2, NULL, FALSE },
{ "shuriken", 12, 5, NULL, FALSE },
{ "spear", 12, 5, NULL, FALSE },
{ NULL, 0 }, /* DO NOT REMOVE: fake entry for dragon's breath */
};
const struct obj_info origws_info[MAXSTICKS] = {
{ "light", 12, 250, NULL, FALSE },
{ "invisibility", 6, 5, NULL, FALSE },
{ "lightning", 3, 330, NULL, FALSE },
{ "fire", 3, 330, NULL, FALSE },
{ "cold", 3, 330, NULL, FALSE },
{ "polymorph", 15, 310, NULL, FALSE },
{ "magic missile", 10, 170, NULL, FALSE },
{ "haste monster", 10, 5, NULL, FALSE },
{ "slow monster", 11, 350, NULL, FALSE },
{ "drain life", 9, 300, NULL, FALSE },
{ "nothing", 1, 5, NULL, FALSE },
{ "teleport away", 6, 340, NULL, FALSE },
{ "teleport to", 6, 50, NULL, FALSE },
{ "cancellation", 5, 280, NULL, FALSE },
};
const struct h_list helpstr[] = {
{'?', " prints help", TRUE},
{'/', " identify object", TRUE},
{'h', " left", TRUE},
{'j', " down", TRUE},
{'k', " up", TRUE},
{'l', " right", TRUE},
{'y', " up & left", TRUE},
{'u', " up & right", TRUE},
{'b', " down & left", TRUE},
{'n', " down & right", TRUE},
{'H', " run left", FALSE},
{'J', " run down", FALSE},
{'K', " run up", FALSE},
{'L', " run right", FALSE},
{'Y', " run up & left", FALSE},
{'U', " run up & right", FALSE},
{'B', " run down & left", FALSE},
{'N', " run down & right", FALSE},
{CTRL('H'), " run left until adjacent", FALSE},
{CTRL('J'), " run down until adjacent", FALSE},
{CTRL('K'), " run up until adjacent", FALSE},
{CTRL('L'), " run right until adjacent", FALSE},
{CTRL('Y'), " run up & left until adjacent", FALSE},
{CTRL('U'), " run up & right until adjacent", FALSE},
{CTRL('B'), " run down & left until adjacent", FALSE},
{CTRL('N'), " run down & right until adjacent", FALSE},
{'\0', " <SHIFT><dir>: run that way", TRUE},
{'\0', " <CTRL><dir>: run till adjacent", TRUE},
{'f', "<dir> fight till death or near death", TRUE},
{'t', "<dir> throw something", TRUE},
{'m', "<dir> move onto without picking up", TRUE},
{'z', "<dir> zap a wand in a direction", TRUE},
{'^', "<dir> identify trap type", TRUE},
{'s', " search for trap/secret door", TRUE},
{'>', " go down a staircase", TRUE},
{'<', " go up a staircase", TRUE},
{'.', " rest for a turn", TRUE},
{',', " pick something up", TRUE},
{'i', " inventory", TRUE},
{'I', " inventory single item", TRUE},
{'q', " quaff potion", TRUE},
{'r', " read scroll", TRUE},
{'e', " eat food", TRUE},
{'w', " wield a weapon", TRUE},
{'W', " wear armor", TRUE},
{'T', " take armor off", TRUE},
{'P', " put on ring", TRUE},
{'R', " remove ring", TRUE},
{'d', " drop object", TRUE},
{'c', " call object", TRUE},
{'a', " repeat last command", TRUE},
{')', " print current weapon", TRUE},
{']', " print current armor", TRUE},
{'=', " print current rings", TRUE},
{'@', " print current stats", TRUE},
{'D', " recall what's been discovered", TRUE},
{'o', " examine/set options", TRUE},
{CTRL('R'), " redraw screen", TRUE},
{CTRL('P'), " repeat last message", TRUE},
{ESCAPE, " cancel command", TRUE},
{'S', " save game", TRUE},
{'Q', " quit", TRUE},
{'!', " shell escape", TRUE},
{'F', "<dir> fight till either of you dies", TRUE},
{'v', " print version number", TRUE},
{0, NULL }
};
const char *inv_t_name[] = {
"Overwrite",
"Slow",
"Clear"
};
const char *tr_name[] = { /* Names of the traps */
"a trapdoor",
"an arrow trap",
"a sleeping gas trap",
"a beartrap",
"a teleport trap",
"a poison dart trap",
"a rust trap",
"a mysterious trap"
};
const int32_t a_class[MAXARMORS] = { /* Armor class for each armor type */
8, /* LEATHER */
7, /* RING_MAIL */
7, /* STUDDED_LEATHER */
6, /* SCALE_MAIL */
5, /* CHAIN_MAIL */
4, /* SPLINT_MAIL */
4, /* BANDED_MAIL */
3, /* PLATE_MAIL */
};
const int32_t e_levels[] = {
10L,
20L,
40L,
80L,
160L,
320L,
640L,
1300L,
2600L,
5200L,
13000L,
26000L,
50000L,
100000L,
200000L,
400000L,
800000L,
2000000L,
4000000L,
8000000L,
0L
};
#include <memory.h>
extern int between;
extern int group;
extern coord nh;
void externs_clear()
{
int i;
after = 0; /* True if we want after daemons */
again = 0; /* Repeating the last command */
noscore = 0; /* Was a wizard sometime */
seenstairs = 0; /* Have seen the stairs (for lsd) */
amulet = FALSE; /* He found the amulet */
door_stop = FALSE; /* Stop running when we pass a door */
fight_flush = FALSE; /* True if toilet input */
firstmove = FALSE; /* First move after setting door_stop */
got_ltc = FALSE; /* We have gotten the local tty chars */
has_hit = FALSE; /* Has a "hit" message pending in msg */
in_shell = FALSE; /* True if executing a shell */
inv_describe = TRUE; /* Say which way items are being used */
jump = FALSE; /* Show running as series of jumps */
kamikaze = FALSE; /* to_death really to DEATH */
lower_msg = FALSE; /* Messages should start w/lower case */
move_on = FALSE; /* Next move shouldn't pick up items */
msg_esc = FALSE; /* Check for ESC from msg's --More-- */
passgo = FALSE; /* Follow passages */
playing = TRUE; /* True until he quits */
q_comm = FALSE; /* Are we executing a 'Q' command? */
running = FALSE; /* True if player is running */
save_msg = TRUE; /* Remember last msg */
see_floor = TRUE; /* Show the lamp illuminated floor */
stat_msg = FALSE; /* Should status() print as a msg() */
terse = FALSE; /* True if we should be short */
to_death = FALSE; /* Fighting is to the death! */
tombstone = TRUE; /* Print out tombstone at end */
#ifdef MASTER
int wizard = FALSE; /* True if allows wizard commands */
#endif
for (i=0; i<26; i++)
pack_used[i] = FALSE;
for (i=0; i<MAXSCROLLS; i++)
if ( s_names[i] != 0 )
free(s_names[i]);
memset(s_names,0,sizeof(s_names));
dir_ch = 0; /* Direction from last get_dir() call */
memset(file_name,0,sizeof(file_name));
memset(huh,0,sizeof(huh));
memset(p_colors,0,sizeof(p_colors));
memset(prbuf,0,sizeof(prbuf));
memset(r_stones,0,sizeof(r_stones));
//memset(whoami,0,sizeof(whoami));
memset(ws_made,0,sizeof(ws_made));
memset(ws_type,0,sizeof(ws_type));
runch = 0; /* Direction player is running */
take = 0; /* Thing she is taking */
orig_dsusp = 0; /* Original dsusp char */
memset(home,0,sizeof(home));
l_last_comm = '\0'; /* Last last_comm */
l_last_dir = '\0'; /* Last last_dir */
last_comm = '\0'; /* Last command typed */
last_dir = '\0'; /* Last direction given */
n_objs = 0; /* # items listed in inventory() call */
ntraps = 0; /* Number of traps on this level */
hungry_state = 0; /* How hungry is he */
inpack = 0; /* Number of things in pack */
inv_type = 0; /* Type of inventory to use */
level = 1; /* What level she is on */
max_hit= 0; /* Max damage done to her in to_death */
max_level = 0; /* Deepest player has gone */
mpos = 0; /* Where cursor is on top line */
no_food = 0; /* Number of levels without food */
count = 0; /* Number of times to repeat command */
if ( scoreboard != NULL )
{
fclose(scoreboard);
scoreboard = NULL; /* File descriptor for score file */
}
food_left = 0; /* Amount of food in hero's stomach */
lastscore = -1; /* Score before this turn */
no_command = 0; /* Number of turns asleep */
no_move = 0; /* Number of turns held in place */
purse = 0; /* How much gold he has */
quiet = 0; /* Number of quiet turns */
vf_hit = 0; /* Number of time flytrap has hit */
memset(&delta,0,sizeof(delta));
memset(&oldpos,0,sizeof(oldpos));
memset(&stairs,0,sizeof(stairs));
memset(places,0,sizeof(places));
cur_armor = NULL; /* What he is wearing */
cur_ring[0] = cur_ring[1] = NULL; /* Which rings are being worn */
cur_weapon = NULL; /* Which weapon he is weilding */
l_last_pick = NULL; /* Last last_pick */
last_pick = NULL; /* Last object picked in get_item() */
lvl_obj = NULL; /* List of objects on this level */
mlist = NULL; /* List of monsters on the level */
memset(&player,0,sizeof(player)); /* His stats */
/* restart of game */
max_stats = orig_max_stats; /* The maximum for the player */
oldrp = 0; /* Roomin(&oldpos) */
memset(rooms,0,sizeof(rooms)); /* One for each room -- A level */
between = 0;
group = 0;
memset(&nh,0,sizeof(nh));
}

192
src/cc/rogue/extern.h Normal file
View File

@@ -0,0 +1,192 @@
/*
* Defines for things used in mach_dep.c
*
* @(#)extern.h 4.35 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#ifndef H_EXTERN_ROGUE_H
#define H_EXTERN_ROGUE_H
#include <stdio.h>
#include <stdbool.h>
#ifdef HAVE_CONFIG_H
#ifdef PDCURSES
#undef HAVE_UNISTD_H
#undef HAVE_LIMITS_H
#undef HAVE_MEMORY_H
#undef HAVE_STRING_H
#endif
#include <stdint.h>
#include "config.h"
#elif defined(__DJGPP__)
#define HAVE_SYS_TYPES_H 1
#define HAVE_PROCESS_H 1
#define HAVE_PWD_H 1
#define HAVE_TERMIOS_H 1
#define HAVE_SETGID 1
#define HAVE_GETGID 1
#define HAVE_SETUID 1
#define HAVE_GETUID 1
#define HAVE_GETPASS 1
#define HAVE_SPAWNL 1
#define HAVE_ALARM 1
#define HAVE_ERASECHAR 1
#define HAVE_KILLCHAR 1
#elif defined(_WIN32)
#define HAVE_CURSES_H
#define HAVE_TERM_H
#define HAVE__SPAWNL
#define HAVE_SYS_TYPES_H
#define HAVE_PROCESS_H
#define HAVE_ERASECHAR 1
#define HAVE_KILLCHAR 1
#elif defined(__CYGWIN__)
#define HAVE_SYS_TYPES_H 1
#define HAVE_PWD_H 1
#define HAVE_PWD_H 1
#define HAVE_SYS_UTSNAME_H 1
#define HAVE_ARPA_INET_H 1
#define HAVE_UNISTD_H 1
#define HAVE_TERMIOS_H 1
#define HAVE_NCURSES_TERM_H 1
#define HAVE_ESCDELAY
#define HAVE_SETGID 1
#define HAVE_GETGID 1
#define HAVE_SETUID 1
#define HAVE_GETUID 1
#define HAVE_GETPASS 1
#define HAVE_GETPWUID 1
#define HAVE_WORKING_FORK 1
#define HAVE_ALARM 1
#define HAVE_SPAWNL 1
#define HAVE__SPAWNL 1
#define HAVE_ERASECHAR 1
#define HAVE_KILLCHAR 1
#else /* POSIX */
#define HAVE_SYS_TYPES_H 1
#define HAVE_PWD_H 1
#define HAVE_PWD_H 1
#define HAVE_SYS_UTSNAME_H 1
#define HAVE_ARPA_INET_H 1
#define HAVE_UNISTD_H 1
#define HAVE_TERMIOS_H 1
#define HAVE_TERM_H 1
#define HAVE_SETGID 1
#define HAVE_GETGID 1
#define HAVE_SETUID 1
#define HAVE_GETUID 1
#define HAVE_SETREUID 1
#define HAVE_SETREGID 1
#define HAVE_GETPASS 1
#define HAVE_GETPWUID 1
#define HAVE_WORKING_FORK 1
#define HAVE_ERASECHAR 1
#define HAVE_KILLCHAR 1
#ifndef _AIX
#define HAVE_GETLOADAVG 1
#endif
#define HAVE_ALARM 1
#endif
#ifdef __DJGPP__
#undef HAVE_GETPWUID /* DJGPP's limited version doesn't even work as documented */
#endif
/*
* Don't change the constants, since they are used for sizes in many
* places in the program.
*/
#include <stdlib.h>
#include <time.h>
#undef SIGTSTP
#define MAXSTR 1024 /* maximum length of strings */
#define MAXLINES 32 /* maximum number of screen lines used */
#define MAXCOLS 80 /* maximum number of screen columns used */
#define RN ((int32_t)((seed = seed*11109+13849) >> 16) & 0xffff)
#ifdef CTRL
#undef CTRL
#endif
#define CTRL(c) (c & 037)
/*
* Now all the global variables
*/
extern bool got_ltc, in_shell;
extern int wizard;
extern char fruit[], prbuf[], whoami[];
extern int orig_dsusp;
extern FILE *scoreboard;
/*
* Function types
*/
void externs_clear();
void auto_save(int);
void endit(int sig);
void fatal(char *);
void getltchars(void);
void leave(int);
void my_exit(int st);
void playltchars(void);
void quit(int);
void resetltchars(void);
void set_order(int *order, int numthings);
void tstp(int ignored);
char *killname(char monst, bool doart);
char *nothing(char type);
char *type_name(int type);
#ifdef CHECKTIME
int checkout(void);
#endif
int md_chmod(char *filename, int mode);
char *md_crypt(char *key, char *salt);
int md_dsuspchar(void);
int md_erasechar(void);
char *md_gethomedir(void);
char *md_getusername(void);
int md_getuid(void);
char *md_getpass(char *prompt);
int md_getpid(void);
char *md_getrealname(int uid);
void md_init(void);
int md_killchar(void);
void md_normaluser(void);
void md_raw_standout(void);
void md_raw_standend(void);
int md_readchar(void);
int md_setdsuspchar(int c);
int md_shellescape(void);
void md_sleep(int s);
int md_suspchar(void);
int md_hasclreol(void);
int md_unlink(char *file);
int md_unlink_open_file(char *file, FILE *inf);
void md_tstpsignal(void);
void md_tstphold(void);
void md_tstpresume(void);
void md_ignoreallsignals(void);
void md_onsignal_autosave(void);
void md_onsignal_exit(void);
void md_onsignal_default(void);
int md_issymlink(char *sp);
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex);
#endif

683
src/cc/rogue/fight.c Normal file
View File

@@ -0,0 +1,683 @@
/*
* All the fighting gets done here
*
* @(#)fight.c 4.67 (Berkeley) 09/06/83
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <stdlib.h>
//#include <curses.h>
//#include <string.h>
//#include <ctype.h>
#include "rogue.h"
//#define EQSTR(a, b) (strcmp(a, b) == 0)
const char *h_names[] = { /* strings for hitting */
" scored an excellent hit on ",
" hit ",
" have injured ",
" swing and hit ",
" scored an excellent hit on ",
" hit ",
" has injured ",
" swings and hits "
};
const char *m_names[] = { /* strings for missing */
" miss",
" swing and miss",
" barely miss",
" don't hit",
" misses",
" swings and misses",
" barely misses",
" doesn't hit",
};
/*
* adjustments to hit probabilities due to strength
*/
static const int str_plus[] = {
-7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
};
/*
* adjustments to damage done due to strength
*/
static const int add_dam[] = {
-7, -6, -5, -4, -3, -2, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 3,
3, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6
};
/*
* fight:
* The player attacks the monster.
*/
int
fight(struct rogue_state *rs,coord *mp, THING *weap, bool thrown)
{
register THING *tp;
register bool did_hit = TRUE;
register char *mname, ch;
/*
* Find the monster we want to fight
*/
#ifdef MASTER
if ((tp = moat(mp->y, mp->x)) == NULL)
debug("Fight what @ %d,%d", mp->y, mp->x);
#else
tp = moat(mp->y, mp->x);
#endif
/*
* Since we are fighting, things are not quiet so no healing takes
* place.
*/
count = 0;
quiet = 0;
runto(rs,mp);
/*
* Let him know it was really a xeroc (if it was one).
*/
ch = '\0';
if (tp->t_type == 'X' && tp->t_disguise != 'X' && !on(player, ISBLIND))
{
tp->t_disguise = 'X';
if (on(player, ISHALU)) {
ch = (char)(rnd(26) + 'A');
mvaddch(tp->t_pos.y, tp->t_pos.x, ch);
}
msg(rs,choose_str("heavy! That's a nasty critter!",
"wait! That's a xeroc!"));
if (!thrown)
return FALSE;
}
mname = set_mname(tp);
did_hit = FALSE;
has_hit = (terse && !to_death);
if (roll_em(&player, tp, weap, thrown))
{
did_hit = FALSE;
if (thrown)
thunk(rs,weap, mname, terse);
else
hit(rs,(char *) NULL, mname, terse);
if (on(player, CANHUH))
{
did_hit = TRUE;
tp->t_flags |= ISHUH;
player.t_flags &= ~CANHUH;
endmsg(rs);
has_hit = FALSE;
msg(rs,"your hands stop glowing %s", pick_color("red"));
}
if (tp->t_stats.s_hpt <= 0)
killed(rs,tp, TRUE);
else if (did_hit && !on(player, ISBLIND))
msg(rs,"%s appears confused", mname);
did_hit = TRUE;
}
else
if (thrown)
bounce(rs,weap, mname, terse);
else
miss(rs,(char *) NULL, mname, terse);
return did_hit;
}
/*
* attack:
* The monster attacks the player
*/
int
attack(struct rogue_state *rs,THING *mp)
{
register char *mname;
register int oldhp;
/*
* Since this is an attack, stop running and any healing that was
* going on at the time.
*/
running = FALSE;
count = 0;
quiet = 0;
if (to_death && !on(*mp, ISTARGET))
{
to_death = FALSE;
kamikaze = FALSE;
}
if (mp->t_type == 'X' && mp->t_disguise != 'X' && !on(player, ISBLIND))
{
mp->t_disguise = 'X';
if (on(player, ISHALU))
mvaddch(mp->t_pos.y, mp->t_pos.x, rnd(26) + 'A');
}
mname = set_mname(mp);
oldhp = pstats.s_hpt;
if (roll_em(mp, &player, (THING *) NULL, FALSE))
{
if (mp->t_type != 'I')
{
if (has_hit)
addmsg(rs,". ");
hit(rs,mname, (char *) NULL, FALSE);
}
else
if (has_hit)
endmsg(rs);
has_hit = FALSE;
if (pstats.s_hpt <= 0)
death(rs,mp->t_type); /* Bye bye life ... */
else if (!kamikaze)
{
oldhp -= pstats.s_hpt;
if (oldhp > max_hit)
max_hit = oldhp;
if (pstats.s_hpt <= max_hit)
to_death = FALSE;
}
if (!on(*mp, ISCANC))
switch (mp->t_type)
{
case 'A':
/*
* If an aquator hits, you can lose armor class.
*/
rust_armor(rs,cur_armor);
when 'I':
/*
* The ice monster freezes you
*/
player.t_flags &= ~ISRUN;
if (!no_command)
{
addmsg(rs,"you are frozen");
if (!terse)
addmsg(rs," by the %s", mname);
endmsg(rs);
}
no_command += rnd(2) + 2;
if (no_command > BORE_LEVEL)
death(rs,'h');
when 'R':
/*
* Rattlesnakes have poisonous bites
*/
if (!save(VS_POISON))
{
if (!ISWEARING(R_SUSTSTR))
{
chg_str(-1);
if (!terse)
msg(rs,"you feel a bite in your leg and now feel weaker");
else
msg(rs,"a bite has weakened you");
}
else if (!to_death)
{
if (!terse)
msg(rs,"a bite momentarily weakens you");
else
msg(rs,"bite has no effect");
}
}
when 'W':
case 'V':
/*
* Wraiths might drain energy levels, and Vampires
* can steal max_hp
*/
if (rnd(100) < (mp->t_type == 'W' ? 15 : 30))
{
register int fewer;
if (mp->t_type == 'W')
{
if (pstats.s_exp == 0)
death(rs,'W'); /* All levels gone */
if (--pstats.s_lvl == 0)
{
pstats.s_exp = 0;
pstats.s_lvl = 1;
}
else
pstats.s_exp = e_levels[pstats.s_lvl-1]+1;
fewer = roll(1, 10);
}
else
fewer = roll(1, 3);
pstats.s_hpt -= fewer;
max_hp -= fewer;
if (pstats.s_hpt <= 0)
pstats.s_hpt = 1;
if (max_hp <= 0)
death(rs,mp->t_type);
msg(rs,"you suddenly feel weaker");
}
when 'F':
/*
* Venus Flytrap stops the poor guy from moving
*/
player.t_flags |= ISHELD;
sprintf(monsters['F'-'A'].m_stats.s_dmg,"%dx1", ++vf_hit);
if (--pstats.s_hpt <= 0)
death(rs,'F');
when 'L':
{
/*
* Leperachaun steals some gold
*/
register int lastpurse;
lastpurse = purse;
purse -= GOLDCALC;
if (!save(VS_MAGIC))
purse -= GOLDCALC + GOLDCALC + GOLDCALC + GOLDCALC;
if (purse < 0)
purse = 0;
remove_mon(rs,&mp->t_pos, mp, FALSE);
mp=NULL;
if (purse != lastpurse)
msg(rs,"your purse feels lighter");
}
when 'N':
{
register THING *obj, *steal;
register int nobj;
/*
* Nymph's steal a magic item, look through the pack
* and pick out one we like.
*/
steal = NULL;
for (nobj = 0, obj = pack; obj != NULL; obj = next(obj))
if (obj != cur_armor && obj != cur_weapon
&& obj != cur_ring[LEFT] && obj != cur_ring[RIGHT]
&& is_magic(obj) && rnd(++nobj) == 0)
steal = obj;
if (steal != NULL)
{
remove_mon(rs,&mp->t_pos, moat(mp->t_pos.y, mp->t_pos.x), FALSE);
mp=NULL;
leave_pack(rs,steal, FALSE, FALSE);
msg(rs,"she stole %s!", inv_name(steal, TRUE));
discard(steal);
}
}
otherwise:
break;
}
}
else if (mp->t_type != 'I')
{
if (has_hit)
{
addmsg(rs,". ");
has_hit = FALSE;
}
if (mp->t_type == 'F')
{
pstats.s_hpt -= vf_hit;
if (pstats.s_hpt <= 0)
death(rs,mp->t_type); /* Bye bye life ... */
}
miss(rs,mname, (char *) NULL, FALSE);
}
if (fight_flush && !to_death)
flush_type();
count = 0;
status(rs);
if (mp == NULL)
return(-1);
else
return(0);
}
/*
* set_mname:
* return the monster name for the given monster
*/
char *
set_mname(THING *tp)
{
int ch;
char *mname;
static char tbuf[MAXSTR] = { 't', 'h', 'e', ' ' };
if (!see_monst(tp) && !on(player, SEEMONST))
return (terse ? (char *)"it" : (char *)"something");
else if (on(player, ISHALU))
{
move(tp->t_pos.y, tp->t_pos.x);
ch = toascii(inch());
if (!isupper(ch))
ch = rnd(26);
else
ch -= 'A';
mname = monsters[ch].m_name;
}
else
mname = monsters[tp->t_type - 'A'].m_name;
strcpy(&tbuf[4], mname);
return tbuf;
}
/*
* swing:
* Returns true if the swing hits
*/
int
swing(int at_lvl, int op_arm, int wplus)
{
int res = rnd(20);
int need = (20 - at_lvl) - op_arm;
return (res + wplus >= need);
}
/*
* roll_em:
* Roll several attacks
*/
bool
roll_em(THING *thatt, THING *thdef, THING *weap, bool hurl)
{
register struct stats *att, *def;
register char *cp;
register int ndice, nsides, def_arm;
register bool did_hit = FALSE;
register int hplus;
register int dplus;
register int damage;
att = &thatt->t_stats;
def = &thdef->t_stats;
if (weap == NULL)
{
cp = att->s_dmg;
dplus = 0;
hplus = 0;
}
else
{
hplus = (weap == NULL ? 0 : weap->o_hplus);
dplus = (weap == NULL ? 0 : weap->o_dplus);
if (weap == cur_weapon)
{
if (ISRING(LEFT, R_ADDDAM))
dplus += cur_ring[LEFT]->o_arm;
else if (ISRING(LEFT, R_ADDHIT))
hplus += cur_ring[LEFT]->o_arm;
if (ISRING(RIGHT, R_ADDDAM))
dplus += cur_ring[RIGHT]->o_arm;
else if (ISRING(RIGHT, R_ADDHIT))
hplus += cur_ring[RIGHT]->o_arm;
}
cp = weap->o_damage;
if (hurl)
{
if ((weap->o_flags&ISMISL) && cur_weapon != NULL &&
cur_weapon->o_which == weap->o_launch)
{
cp = weap->o_hurldmg;
hplus += cur_weapon->o_hplus;
dplus += cur_weapon->o_dplus;
}
else if (weap->o_launch < 0)
cp = weap->o_hurldmg;
}
}
/*
* If the creature being attacked is not running (alseep or held)
* then the attacker gets a plus four bonus to hit.
*/
if (!on(*thdef, ISRUN))
hplus += 4;
def_arm = def->s_arm;
if (def == &pstats)
{
if (cur_armor != NULL)
def_arm = cur_armor->o_arm;
if (ISRING(LEFT, R_PROTECT))
def_arm -= cur_ring[LEFT]->o_arm;
if (ISRING(RIGHT, R_PROTECT))
def_arm -= cur_ring[RIGHT]->o_arm;
}
while(cp != NULL && *cp != '\0')
{
ndice = atoi(cp);
if ((cp = strchr(cp, 'x')) == NULL)
break;
nsides = atoi(++cp);
if (swing(att->s_lvl, def_arm, hplus + str_plus[att->s_str]))
{
int proll;
proll = roll(ndice, nsides);
#ifdef MASTER
if (ndice + nsides > 0 && proll <= 0)
debug("Damage for %dx%d came out %d, dplus = %d, add_dam = %d, def_arm = %d", ndice, nsides, proll, dplus, add_dam[att->s_str], def_arm);
#endif
damage = dplus + proll + add_dam[att->s_str];
def->s_hpt -= max(0, damage);
did_hit = TRUE;
}
if ((cp = strchr(cp, '/')) == NULL)
break;
cp++;
}
return did_hit;
}
/*
* prname:
* The print name of a combatant
*/
char *
prname(char *mname, bool upper)
{
static char tbuf[MAXSTR];
*tbuf = '\0';
if (mname == 0)
strcpy(tbuf, "you");
else
strcpy(tbuf, mname);
if (upper)
*tbuf = (char) toupper(*tbuf);
return tbuf;
}
/*
* thunk:
* A missile hits a monster
*/
void
thunk(struct rogue_state *rs,THING *weap, char *mname, bool noend)
{
if (to_death)
return;
if (weap->o_type == WEAPON)
addmsg(rs,"the %s hits ", weap_info[weap->o_which].oi_name);
else
addmsg(rs,"you hit ");
addmsg(rs,"%s", mname);
if (!noend)
endmsg(rs);
}
/*
* hit:
* Print a message to indicate a succesful hit
*/
void
hit(struct rogue_state *rs,char *er, char *ee, bool noend)
{
int32_t i; const char *s;
if (to_death)
return;
addmsg(rs,prname(er, TRUE));
if (terse)
s = " hit";
else
{
i = rnd(4);
if (er != NULL)
i += 4;
s = h_names[i];
}
addmsg(rs,(char *)s);
if (!terse)
addmsg(rs,prname(ee, FALSE));
if (!noend)
endmsg(rs);
}
/*
* miss:
* Print a message to indicate a poor swing
*/
void
miss(struct rogue_state *rs,char *er, char *ee, bool noend)
{
int i;
if (to_death)
return;
addmsg(rs,prname(er, TRUE));
if (terse)
i = 0;
else
i = rnd(4);
if (er != NULL)
i += 4;
addmsg(rs,(char *)m_names[i]);
if (!terse)
addmsg(rs," %s", prname(ee, FALSE));
if (!noend)
endmsg(rs);
}
/*
* bounce:
* A missile misses a monster
*/
void
bounce(struct rogue_state *rs,THING *weap, char *mname, bool noend)
{
if (to_death)
return;
if (weap->o_type == WEAPON)
addmsg(rs,"the %s misses ", weap_info[weap->o_which].oi_name);
else
addmsg(rs,"you missed ");
addmsg(rs,mname);
if (!noend)
endmsg(rs);
}
/*
* remove_mon:
* Remove a monster from the screen
*/
void
remove_mon(struct rogue_state *rs,coord *mp, THING *tp, bool waskill)
{
register THING *obj, *nexti;
for (obj = tp->t_pack; obj != NULL; obj = nexti)
{
nexti = next(obj);
obj->o_pos = tp->t_pos;
detach(tp->t_pack, obj);
if (waskill)
fall(rs,obj, FALSE);
else
discard(obj);
}
moat(mp->y, mp->x) = NULL;
mvaddch(mp->y, mp->x, tp->t_oldch);
detach(mlist, tp);
if (on(*tp, ISTARGET))
{
kamikaze = FALSE;
to_death = FALSE;
if (fight_flush)
flush_type();
}
discard(tp);
}
/*
* killed:
* Called to put a monster to death
*/
void
killed(struct rogue_state *rs,THING *tp, bool pr)
{
char *mname;
pstats.s_exp += tp->t_stats.s_exp;
/*
* If the monster was a venus flytrap, un-hold him
*/
switch (tp->t_type)
{
case 'F':
player.t_flags &= ~ISHELD;
vf_hit = 0;
strcpy(monsters['F'-'A'].m_stats.s_dmg, "000x0");
when 'L':
{
THING *gold;
if (fallpos(&tp->t_pos, &tp->t_room->r_gold) && level >= max_level)
{
gold = new_item();
gold->o_type = GOLD;
gold->o_goldval = GOLDCALC;
if (save(VS_MAGIC))
gold->o_goldval += GOLDCALC + GOLDCALC
+ GOLDCALC + GOLDCALC;
attach(tp->t_pack, gold);
}
}
}
/*
* Get rid of the monster.
*/
mname = set_mname(tp);
remove_mon(rs,&tp->t_pos, tp, TRUE);
if (pr)
{
if (has_hit)
{
addmsg(rs,". Defeated ");
has_hit = FALSE;
}
else
{
if (!terse)
addmsg(rs,"you have ");
addmsg(rs,"defeated ");
}
msg(rs,mname);
}
/*
* Do adjustments if he went up a level
*/
check_level(rs);
if (fight_flush)
flush_type();
}

480
src/cc/rogue/init.c Normal file
View File

@@ -0,0 +1,480 @@
/*
* global variable initializaton
*
* @(#)init.c 4.31 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <stdlib.h>
//#include <curses.h>
//#include <ctype.h>
//#include <string.h>
#include "rogue.h"
/*
* init_player:
* Roll her up
*/
void rogue_restoreobject(THING *o,struct rogue_packitem *item);
void restore_player(struct rogue_state *rs)
{
int32_t i; THING *obj;
//rs->P.gold = purse;
max_hp = rs->P.hitpoints;
pstats.s_str = max_stats.s_str = rs->P.strength;
pstats.s_lvl = rs->P.level;
pstats.s_exp = rs->P.experience;
for (i=0; i<rs->P.packsize; i++)
{
obj = new_item();
rogue_restoreobject(obj,&rs->P.roguepack[i]);
add_pack(rs,obj,TRUE);
}
}
void init_player(struct rogue_state *rs)
{
register THING *obj; int32_t i;
pstats = max_stats;
food_left = HUNGERTIME;
if ( rs->restoring != 0 )
{
// duplicate rng usage of normal case
obj = new_item();
init_weapon(obj, MACE);
free(obj);
obj = new_item();
init_weapon(obj, BOW);
free(obj);
obj = new_item();
init_weapon(obj, ARROW);
obj->o_count = rnd(15) + 25;
free(obj);
}
else
{
/*
* Give him some food
*/
obj = new_item();
obj->o_type = FOOD;
obj->o_count = 1;
add_pack(rs,obj, TRUE);
/*
* And his suit of armor
*/
obj = new_item();
obj->o_type = ARMOR;
obj->o_which = RING_MAIL;
obj->o_arm = a_class[RING_MAIL] - 1;
obj->o_flags |= ISKNOW;
obj->o_count = 1;
cur_armor = obj;
add_pack(rs,obj, TRUE);
/*
* Give him his weaponry. First a mace.
*/
obj = new_item();
init_weapon(obj, MACE);
obj->o_hplus = 1;
obj->o_dplus = 1;
obj->o_flags |= ISKNOW;
add_pack(rs,obj, TRUE);
cur_weapon = obj;
/*
* Now a +1 bow
*/
obj = new_item();
init_weapon(obj, BOW);
obj->o_hplus = 1;
obj->o_flags |= ISKNOW;
add_pack(rs,obj, TRUE);
/*
* Now some arrows
*/
obj = new_item();
init_weapon(obj, ARROW);
obj->o_count = rnd(15) + 25;
obj->o_flags |= ISKNOW;
add_pack(rs,obj, TRUE);
//fprintf(stderr,"initial o_count.%d\n",obj->o_count); sleep(3);
}
}
/*
* Contains defintions and functions for dealing with things like
* potions and scrolls
*/
const char *rainbow[] = {
"amber",
"aquamarine",
"black",
"blue",
"brown",
"clear",
"crimson",
"cyan",
"ecru",
"gold",
"green",
"grey",
"magenta",
"orange",
"pink",
"plaid",
"purple",
"red",
"silver",
"tan",
"tangerine",
"topaz",
"turquoise",
"vermilion",
"violet",
"white",
"yellow",
};
#define NCOLORS (sizeof rainbow / sizeof (char *))
int cNCOLORS = NCOLORS;
static const char *sylls[] = {
"a", "ab", "ag", "aks", "ala", "an", "app", "arg", "arze", "ash",
"bek", "bie", "bit", "bjor", "blu", "bot", "bu", "byt", "comp",
"con", "cos", "cre", "dalf", "dan", "den", "do", "e", "eep", "el",
"eng", "er", "ere", "erk", "esh", "evs", "fa", "fid", "fri", "fu",
"gan", "gar", "glen", "gop", "gre", "ha", "hyd", "i", "ing", "ip",
"ish", "it", "ite", "iv", "jo", "kho", "kli", "klis", "la", "lech",
"mar", "me", "mi", "mic", "mik", "mon", "mung", "mur", "nej",
"nelg", "nep", "ner", "nes", "nes", "nih", "nin", "o", "od", "ood",
"org", "orn", "ox", "oxy", "pay", "ple", "plu", "po", "pot",
"prok", "re", "rea", "rhov", "ri", "ro", "rog", "rok", "rol", "sa",
"san", "sat", "sef", "seh", "shu", "ski", "sna", "sne", "snik",
"sno", "so", "sol", "sri", "sta", "sun", "ta", "tab", "tem",
"ther", "ti", "tox", "trol", "tue", "turs", "u", "ulk", "um", "un",
"uni", "ur", "val", "viv", "vly", "vom", "wah", "wed", "werg",
"wex", "whon", "wun", "xo", "y", "yot", "yu", "zant", "zeb", "zim",
"zok", "zon", "zum",
};
const STONE stones[] = {
{ "agate", 25},
{ "alexandrite", 40},
{ "amethyst", 50},
{ "carnelian", 40},
{ "diamond", 300},
{ "emerald", 300},
{ "germanium", 225},
{ "granite", 5},
{ "garnet", 50},
{ "jade", 150},
{ "kryptonite", 300},
{ "lapis lazuli", 50},
{ "moonstone", 50},
{ "obsidian", 15},
{ "onyx", 60},
{ "opal", 200},
{ "pearl", 220},
{ "peridot", 63},
{ "ruby", 350},
{ "sapphire", 285},
{ "stibotantalite", 200},
{ "tiger eye", 50},
{ "topaz", 60},
{ "turquoise", 70},
{ "taaffeite", 300},
{ "zircon", 80},
};
#define NSTONES (sizeof stones / sizeof (STONE))
int cNSTONES = NSTONES;
const char *wood[] = {
"avocado wood",
"balsa",
"bamboo",
"banyan",
"birch",
"cedar",
"cherry",
"cinnibar",
"cypress",
"dogwood",
"driftwood",
"ebony",
"elm",
"eucalyptus",
"fall",
"hemlock",
"holly",
"ironwood",
"kukui wood",
"mahogany",
"manzanita",
"maple",
"oaken",
"persimmon wood",
"pecan",
"pine",
"poplar",
"redwood",
"rosewood",
"spruce",
"teak",
"walnut",
"zebrawood",
};
#define NWOOD (sizeof wood / sizeof (char *))
int cNWOOD = NWOOD;
const char *metal[] = {
"aluminum",
"beryllium",
"bone",
"brass",
"bronze",
"copper",
"electrum",
"gold",
"iron",
"lead",
"magnesium",
"mercury",
"nickel",
"pewter",
"platinum",
"steel",
"silver",
"silicon",
"tin",
"titanium",
"tungsten",
"zinc",
};
#define NMETAL (sizeof metal / sizeof (char *))
int cNMETAL = NMETAL;
#define MAX3(a,b,c) (a > b ? (a > c ? a : c) : (b > c ? b : c))
static bool used[MAX3(NCOLORS, NSTONES, NWOOD)];
/*
* init_colors:
* Initialize the potion color scheme for this time
*/
void
init_colors()
{
register int i, j;
memset(used,0,sizeof(used));
for (i = 0; i < NCOLORS; i++)
used[i] = FALSE;
for (i = 0; i < MAXPOTIONS; i++)
{
do
j = rnd(NCOLORS);
until (!used[j]);
used[j] = TRUE;
p_colors[i] = rainbow[j];
}
}
/*
* init_names:
* Generate the names of the various scrolls
*/
#define MAXNAME 40 /* Max number of characters in a name */
void
init_names()
{
register int nsyl;
register char *cp; const char *sp;
register int i, nwords;
for (i = 0; i < MAXSCROLLS; i++)
{
cp = prbuf;
nwords = rnd(3) + 2;
while (nwords--)
{
nsyl = rnd(3) + 1;
while (nsyl--)
{
sp = sylls[rnd((sizeof sylls) / (sizeof (char *)))];
if (&cp[strlen(sp)] > &prbuf[MAXNAME])
break;
while (*sp)
*cp++ = *sp++;
}
*cp++ = ' ';
}
*--cp = '\0';
s_names[i] = (char *) malloc((unsigned) strlen(prbuf)+1);
strcpy(s_names[i], prbuf);
}
}
/*
* init_stones:
* Initialize the ring stone setting scheme for this time
*/
void
init_stones()
{
register int i, j;
for (i = 0; i < NSTONES; i++)
used[i] = FALSE;
for (i = 0; i < MAXRINGS; i++)
{
do
j = rnd(NSTONES);
until (!used[j]);
used[j] = TRUE;
r_stones[i] = stones[j].st_name;
ring_info[i].oi_worth += stones[j].st_value;
}
}
/*
* init_materials:
* Initialize the construction materials for wands and staffs
*/
void
init_materials()
{
register int i, j;
register const char *str;
static bool metused[NMETAL];
memset(metused,0,sizeof(metused));
for (i = 0; i < NWOOD; i++)
used[i] = FALSE;
for (i = 0; i < NMETAL; i++)
metused[i] = FALSE;
for (i = 0; i < MAXSTICKS; i++)
{
for (;;)
if (rnd(2) == 0)
{
j = rnd(NMETAL);
if (!metused[j])
{
ws_type[i] = "wand";
str = metal[j];
metused[j] = TRUE;
break;
}
}
else
{
j = rnd(NWOOD);
if (!used[j])
{
ws_type[i] = "staff";
str = wood[j];
used[j] = TRUE;
break;
}
}
ws_made[i] = str;
}
}
#ifdef MASTER
# define NT NUMTHINGS, "things"
# define MP MAXPOTIONS, "potions"
# define MS MAXSCROLLS, "scrolls"
# define MR MAXRINGS, "rings"
# define MWS MAXSTICKS, "sticks"
# define MW MAXWEAPONS, "weapons"
# define MA MAXARMORS, "armor"
#else
# define NT NUMTHINGS
# define MP MAXPOTIONS
# define MS MAXSCROLLS
# define MR MAXRINGS
# define MWS MAXSTICKS
# define MW MAXWEAPONS
# define MA MAXARMORS
#endif
/*
* sumprobs:
* Sum up the probabilities for items appearing
*/
void
sumprobs(struct obj_info *info, int bound
#ifdef MASTER
, char *name
#endif
)
{
#ifdef MASTER
struct obj_info *start = info;
#endif
struct obj_info *endp;
endp = info + bound;
while (++info < endp)
info->oi_prob += (info - 1)->oi_prob;
#ifdef MASTER
badcheck(name, start, bound);
#endif
}
/*
* init_probs:
* Initialize the probabilities for the various items
*/
void
init_probs()
{
sumprobs(things, NT);
sumprobs(pot_info, MP);
sumprobs(scr_info, MS);
sumprobs(ring_info, MR);
sumprobs(ws_info, MWS);
sumprobs(weap_info, MW);
sumprobs(arm_info, MA);
}
#ifdef MASTER
/*
* badcheck:
* Check to see if a series of probabilities sums to 100
*/
void
badcheck(char *name, struct obj_info *info, int bound)
{
register struct obj_info *end;
if (info[bound - 1].oi_prob == 100)
return;
printf("\nBad percentages for %s (bound = %d):\n", name, bound);
for (end = &info[bound]; info < end; info++)
printf("%3d%% %s\n", info->oi_prob, info->oi_name);
printf("[hit RETURN to continue]");
fflush(stdout);
while (getchar() != '\n')
continue;
}
#endif
/*
* pick_color:
* If he is halucinating, pick a random color name and return it,
* otherwise return the given color.
*/
char *
pick_color(char *col)
{
return (on(player, ISHALU) ? (char *)rainbow[rnd(NCOLORS)] : col);
}

323
src/cc/rogue/install-sh Executable file
View File

@@ -0,0 +1,323 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2005-05-14.22
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch. It can only install one file at a time, a restriction
# shared with many OS's install programs.
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
chmodcmd="$chmodprog 0755"
chowncmd=
chgrpcmd=
stripcmd=
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=
dst=
dir_arg=
dstarg=
no_target_directory=
usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
-c (ignored)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
--help display this help and exit.
--version display version info and exit.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
"
while test -n "$1"; do
case $1 in
-c) shift
continue;;
-d) dir_arg=true
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
--help) echo "$usage"; exit $?;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-s) stripcmd=$stripprog
shift
continue;;
-t) dstarg=$2
shift
shift
continue;;
-T) no_target_directory=true
shift
continue;;
--version) echo "$0 $scriptversion"; exit $?;;
*) # When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
test -n "$dir_arg$dstarg" && break
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dstarg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dstarg"
shift # fnord
fi
shift # arg
dstarg=$arg
done
break;;
esac
done
if test -z "$1"; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
for src
do
# Protect names starting with `-'.
case $src in
-*) src=./$src ;;
esac
if test -n "$dir_arg"; then
dst=$src
src=
if test -d "$dst"; then
mkdircmd=:
chmodcmd=
else
mkdircmd=$mkdirprog
fi
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dstarg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dstarg
# Protect names starting with `-'.
case $dst in
-*) dst=./$dst ;;
esac
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dstarg: Is a directory" >&2
exit 1
fi
dst=$dst/`basename "$src"`
fi
fi
# This sed command emulates the dirname command.
dstdir=`echo "$dst" | sed -e 's,/*$,,;s,[^/]*$,,;s,/*$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# Skip lots of stat calls in the usual case.
if test ! -d "$dstdir"; then
defaultIFS='
'
IFS="${IFS-$defaultIFS}"
oIFS=$IFS
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set x `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'`
shift
IFS=$oIFS
pathcomp=
while test $# -ne 0 ; do
pathcomp=$pathcomp$1
shift
if test ! -d "$pathcomp"; then
$mkdirprog "$pathcomp"
# mkdir can fail with a `File exist' error in case several
# install-sh are creating the directory concurrently. This
# is OK.
test -d "$pathcomp" || exit
fi
pathcomp=$pathcomp/
done
fi
if test -n "$dir_arg"; then
$doit $mkdircmd "$dst" \
&& { test -z "$chowncmd" || $doit $chowncmd "$dst"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dst"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd "$dst"; }
else
dstfile=`basename "$dst"`
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
trap '(exit $?); exit' 1 2 13 15
# Copy the file name to the temp name.
$doit $cpprog "$src" "$dsttmp" &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd "$dsttmp"; } &&
# Now rename the file to the real destination.
{ $doit $mvcmd -f "$dsttmp" "$dstdir/$dstfile" 2>/dev/null \
|| {
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
if test -f "$dstdir/$dstfile"; then
$doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null \
|| $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null \
|| {
echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2
(exit 1); exit 1
}
else
:
fi
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dstdir/$dstfile"
}
}
fi || { (exit 1); exit 1; }
done
# The final little trick to "correctly" pass the exit status to the exit trap.
{
(exit 0); exit 0
}
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

321
src/cc/rogue/io.c Normal file
View File

@@ -0,0 +1,321 @@
/*
* Various input/output functions
*
* @(#)io.c 4.32 (Berkeley) 02/05/99
*/
//#include <stdarg.h>
//#include <curses.h>
//#include <ctype.h>
//#include <string.h>
#include "rogue.h"
/*
* msg:
* Display a message at the top of the screen.
*/
#define MAXMSG (NUMCOLS - sizeof "--More--")
static char msgbuf[2*MAXMSG+1];
static int newpos = 0;
/* VARARGS1 */
int
msg(struct rogue_state *rs,char *fmt, ...)
{
va_list args;
/*
* if the string is "", just clear the line
*/
if (*fmt == '\0')
{
move(0, 0);
clrtoeol();
mpos = 0;
return ~ESCAPE;
}
/*
* otherwise add to the message and flush it out
*/
va_start(args, fmt);
doadd(rs,fmt, args);
va_end(args);
return endmsg(rs);
}
/*
* addmsg:
* Add things to the current message
*/
/* VARARGS1 */
void
addmsg(struct rogue_state *rs,char *fmt, ...)
{
va_list args;
va_start(args, fmt);
doadd(rs,fmt, args);
va_end(args);
}
/*
* endmsg:
* Display a new msg (giving him a chance to see the previous one
* if it is up there with the --More--)
*/
int
endmsg(struct rogue_state *rs)
{
char ch;
if (save_msg)
strcpy(huh, msgbuf);
if (mpos)
{
look(rs,FALSE);
mvaddstr(0, mpos, "--More--");
if ( rs->sleeptime != 0 )
refresh();
if (!msg_esc)
wait_for(rs,' ');
else
{
while ((ch = readchar(rs)) != ' ')
if (ch == ESCAPE)
{
msgbuf[0] = '\0';
mpos = 0;
newpos = 0;
msgbuf[0] = '\0';
return ESCAPE;
}
}
}
/*
* All messages should start with uppercase, except ones that
* start with a pack addressing character
*/
if (islower(msgbuf[0]) && !lower_msg && msgbuf[1] != ')')
msgbuf[0] = (char) toupper(msgbuf[0]);
mvaddstr(0, 0, msgbuf);
clrtoeol();
mpos = newpos;
newpos = 0;
msgbuf[0] = '\0';
if ( rs->sleeptime != 0 )
refresh();
return ~ESCAPE;
}
/*
* doadd:
* Perform an add onto the message buffer
*/
void
doadd(struct rogue_state *rs,char *fmt, va_list args)
{
static char buf[MAXSTR];
/*
* Do the printf into buf
*/
vsprintf(buf, fmt, args);
if (strlen(buf) + newpos >= MAXMSG)
endmsg(rs);
strcat(msgbuf, buf);
newpos = (int) strlen(msgbuf);
}
/*
* step_ok:
* Returns true if it is ok to step on ch
*/
int
step_ok(int ch)
{
switch (ch)
{
case ' ':
case '|':
case '-':
return FALSE;
default:
return (!isalpha(ch));
}
}
/*
* readchar:
* Reads and returns a character, checking for gross input errors
*/
char
readchar(struct rogue_state *rs)
{
char ch = -1;
if ( rs != 0 && rs->guiflag == 0 )
{
static uint32_t counter;
if ( rs->ind < rs->numkeys )
{
//if ( rs->ind == rs->numkeys-1 )
// rs->replaydone = (uint32_t)time(NULL);
//fprintf(stderr,"(%c) ",rs->keystrokes[rs->ind]);
return(rs->keystrokes[rs->ind++]);
}
if ( rs->replaydone != 0 && counter++ < 3 )
fprintf(stderr,"replay finished but readchar called\n");
rs->replaydone = (uint32_t)time(NULL);
//if ( (rand() & 1) == 0 )
// return(ESCAPE);
//else
if ( counter < 3 || (counter & 1) == 0 )
return('y');
else return(ESCAPE);
}
if ( rs == 0 || rs->guiflag != 0 )
{
ch = (char) md_readchar();
if (ch == 3)
{
quit(0);
return(27);
}
if ( rs != 0 && rs->guiflag != 0 )
{
if ( rs->num < sizeof(rs->buffered) )
{
rs->buffered[rs->num++] = ch;
if ( rs->num > (sizeof(rs->buffered)*9)/10 && rs->needflush == 0 )
{
rs->needflush = (uint32_t)time(NULL);
//fprintf(stderr,"needflush.%u %d of %d\n",rs->needflush,rs->num,(int32_t)sizeof(rs->buffered));
//sleep(3);
}
} else fprintf(stderr,"buffer filled without flushed\n");
}
} else fprintf(stderr,"readchar rs.%p non-gui error?\n",rs);
return(ch);
}
/*
* status:
* Display the important stats line. Keep the cursor where it was.
*/
void
status(struct rogue_state *rs)
{
register int oy, ox, temp;
static int hpwidth = 0;
static int s_hungry = 0;
static int s_lvl = 0;
static int s_pur = -1;
static int s_hp = 0;
static int s_arm = 0;
static str_t s_str = 0;
static int s_exp = 0;
static char *state_name[] =
{
"", "Hungry", "Weak", "Faint"
};
/*
* If nothing has changed since the last status, don't
* bother.
*/
temp = (cur_armor != NULL ? cur_armor->o_arm : pstats.s_arm);
if (s_hp == pstats.s_hpt && s_exp == pstats.s_exp && s_pur == purse
&& s_arm == temp && s_str == pstats.s_str && s_lvl == level
&& s_hungry == hungry_state
&& !stat_msg
)
return;
s_arm = temp;
getyx(stdscr, oy, ox);
if (s_hp != max_hp)
{
temp = max_hp;
s_hp = max_hp;
for (hpwidth = 0; temp; hpwidth++)
temp /= 10;
}
/*
* Save current status
*/
s_lvl = level;
s_pur = purse;
s_hp = pstats.s_hpt;
s_str = pstats.s_str;
s_exp = pstats.s_exp;
s_hungry = hungry_state;
if (stat_msg)
{
move(0, 0);
msg(rs,"Level: %d Gold: %-5d Hp: %*d(%*d) Str: %2d(%d) Arm: %-2d Exp: %d/%ld %s",
level, purse, hpwidth, pstats.s_hpt, hpwidth, max_hp, pstats.s_str,
max_stats.s_str, 10 - s_arm, pstats.s_lvl, pstats.s_exp,
state_name[hungry_state]);
}
else
{
move(STATLINE, 0);
printw("Level: %d Gold: %-5d Hp: %*d(%*d) Str: %2d(%d) Arm: %-2d Exp: %d/%d %s",
level, purse, hpwidth, pstats.s_hpt, hpwidth, max_hp, pstats.s_str,
max_stats.s_str, 10 - s_arm, pstats.s_lvl, pstats.s_exp,
state_name[hungry_state]);
}
clrtoeol();
move(oy, ox);
}
/*
* wait_for
* Sit around until the guy types the right key
*/
void
wait_for(struct rogue_state *rs,int ch)
{
register char c;
if (ch == '\n')
while ((c = readchar(rs)) != '\n' && c != '\r')
{
if ( rs->replaydone != 0 )
return;
continue;
}
else
while (readchar(rs) != ch)
{
if ( rs->replaydone != 0 )
return;
continue;
}
}
/*
* show_win:
* Function used to display a window and wait before returning
*/
void
show_win(struct rogue_state *rs,char *message)
{
WINDOW *win;
win = hw;
wmove(win, 0, 0);
waddstr(win, message);
touchwin(win);
wmove(win, hero.y, hero.x);
wrefresh(win);
wait_for(rs,' ');
clearok(curscr, TRUE);
touchwin(stdscr);
}

151
src/cc/rogue/list.c Normal file
View File

@@ -0,0 +1,151 @@
/*
* Functions for dealing with linked lists of goodies
*
* @(#)list.c 4.12 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <stdlib.h>
//#include <curses.h>
//#include <memory.h>
#include "rogue.h"
#ifdef MASTER
int total = 0; /* total dynamic memory bytes */
#endif
/*
* detach:
* takes an item out of whatever linked list it might be in
*/
void
_detach(THING **list, THING *item)
{
if (*list == item)
*list = next(item);
if (prev(item) != NULL)
item->l_prev->l_next = next(item);
if (next(item) != NULL)
item->l_next->l_prev = prev(item);
item->l_next = NULL;
item->l_prev = NULL;
}
/*
* _attach:
* add an item to the head of a list
*/
void
_attach(THING **list, THING *item)
{
if (*list != NULL)
{
item->l_next = *list;
(*list)->l_prev = item;
item->l_prev = NULL;
}
else
{
item->l_next = NULL;
item->l_prev = NULL;
}
*list = item;
}
/*
* _free_list:
* Throw the whole blamed thing away
*/
void
_free_list(THING **ptr)
{
THING *item;
while (*ptr != NULL)
{
item = *ptr;
*ptr = next(item);
discard(item);
}
}
/*
* discard:
* Free up an item
*/
int32_t itemcounter;
THING *thingptrs[100000];
int32_t numptrs;
void
discard(THING *item)
{
#ifdef MASTER
total--;
#endif
if ( 0 )
{
int32_t i;
for (i=0; i<numptrs; i++)
if ( item == thingptrs[i] )
{
thingptrs[i] = thingptrs[--numptrs];
thingptrs[numptrs] = 0;
break;
}
}
itemcounter--;
free((char *) item);
}
void garbage_collect()
{
return;
int32_t i;
fprintf(stderr,"numptrs.%d free them\n",numptrs);
for (i=0; i<numptrs; i++)
{
//fprintf(stderr,"%p _t_type.%d otype.%d (%c)\n",thingptrs[i],thingptrs[i]->_t._t_type,thingptrs[i]->o_type,thingptrs[i]->o_type);
free(thingptrs[i]);
}
memset(thingptrs,0,sizeof(thingptrs));
numptrs = 0;
}
/*
* new_item
* Get a new item with a specified size
*/
THING *
new_item(void)
{
THING *item;
#ifdef MASTER
if ((item = (THING *)calloc(1, sizeof *item)) == NULL)
msg(rs,"ran out of memory after %d items", total);
else
total++;
#else
item = (THING *)calloc(1, sizeof *item);
#endif
if ( 0 )
{
thingptrs[numptrs++] = item;
if ( (++itemcounter % 100) == 0 )
fprintf(stderr,"itemcounter.%d\n",itemcounter);
}
item->l_next = NULL;
item->l_prev = NULL;
return item;
}

459
src/cc/rogue/mach_dep.c Normal file
View File

@@ -0,0 +1,459 @@
/*
* Various installation dependent routines
*
* @(#)mach_dep.c 4.37 (Berkeley) 05/23/83
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
/*
* The various tuneable defines are:
*
* SCOREFILE Where/if the score file should live.
* ALLSCORES Score file is top ten scores, not top ten
* players. This is only useful when only a few
* people will be playing; otherwise the score file
* gets hogged by just a few people.
* NUMSCORES Number of scores in the score file (default 10).
* NUMNAME String version of NUMSCORES (first character
* should be capitalized) (default "Ten").
* MAXLOAD What (if any) the maximum load average should be
* when people are playing. Since it is divided
* by 10, to specify a load limit of 4.0, MAXLOAD
* should be "40". If defined, then
* LOADAV Should it use it's own routine to get
* the load average?
* NAMELIST If so, where does the system namelist
* hide?
* MAXUSERS What (if any) the maximum user count should be
* when people are playing. If defined, then
* UCOUNT Should it use it's own routine to count
* users?
* UTMP If so, where does the user list hide?
* CHECKTIME How often/if it should check during the game
* for high load average.
*/
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <time.h>
//#include <curses.h>
#include "rogue.h"
#include "extern.h"
#define NOOP(x) (x += 0)
# ifndef NUMSCORES
# define NUMSCORES 10
# define NUMNAME "Ten"
# endif
unsigned int numscores = NUMSCORES;
char *Numname = NUMNAME;
# ifdef ALLSCORES
bool allscore = TRUE;
# else /* ALLSCORES */
bool allscore = FALSE;
# endif /* ALLSCORES */
#ifdef CHECKTIME
static int num_checks; /* times we've gone over in checkout() */
#endif /* CHECKTIME */
/*
* init_check:
* Check out too see if it is proper to play the game now
*/
void
init_check()
{
#if defined(MAXLOAD) || defined(MAXUSERS)
if (too_much())
{
printf("Sorry, %s, but the system is too loaded now.\n", whoami);
printf("Try again later. Meanwhile, why not enjoy a%s %s?\n",
vowelstr(fruit), fruit);
if (author())
printf("However, since you're a good guy, it's up to you\n");
else
exit(1);
}
#endif
}
/*
* open_score:
* Open up the score file for future use
*/
void
open_score()
{
#ifdef SCOREFILE
char *scorefile = SCOREFILE;
/*
* We drop setgid privileges after opening the score file, so subsequent
* open()'s will fail. Just reuse the earlier filehandle.
*/
if (scoreboard != NULL) {
rewind(scoreboard);
return;
}
scoreboard = fopen(scorefile, "r+");
if ((scoreboard == NULL) && (errno == ENOENT))
{
scoreboard = fopen(scorefile, "w+");
md_chmod(scorefile,0664);
}
if (scoreboard == NULL) {
fprintf(stderr, "Could not open %s for writing: %s\n", scorefile, strerror(errno));
fflush(stderr);
}
#else
scoreboard = NULL;
#endif
}
/*
* setup:
* Get starting setup for all games
*/
void
setup()
{
#ifdef CHECKTIME
int checkout();
#endif
#ifdef DUMP
md_onsignal_autosave();
#else
md_onsignal_default();
#endif
#ifdef CHECKTIME
md_start_checkout_timer(CHECKTIME*60);
num_checks = 0;
#endif
raw(); /* Raw mode */
noecho(); /* Echo off */
keypad(stdscr,1);
getltchars(); /* get the local tty chars */
}
/*
* getltchars:
* Get the local tty chars for later use
*/
void
getltchars()
{
got_ltc = TRUE;
orig_dsusp = md_dsuspchar();
md_setdsuspchar( md_suspchar() );
}
/*
* resetltchars:
* Reset the local tty chars to original values.
*/
void
resetltchars(void)
{
if (got_ltc) {
md_setdsuspchar(orig_dsusp);
}
}
/*
* playltchars:
* Set local tty chars to the values we use when playing.
*/
void
playltchars(void)
{
if (got_ltc) {
md_setdsuspchar( md_suspchar() );
}
}
/*
* start_score:
* Start the scoring sequence
*/
void
start_score()
{
#ifdef CHECKTIME
md_stop_checkout_timer();
#endif
}
/*
* is_symlink:
* See if the file has a symbolic link
*/
bool
is_symlink(char *sp)
{
#ifdef S_IFLNK
struct stat sbuf2;
if (lstat(sp, &sbuf2) < 0)
return FALSE;
else
return ((sbuf2.st_mode & S_IFMT) != S_IFREG);
#else
NOOP(sp);
return FALSE;
#endif
}
#if defined(MAXLOAD) || defined(MAXUSERS)
/*
* too_much:
* See if the system is being used too much for this game
*/
bool
too_much()
{
#ifdef MAXLOAD
double avec[3];
#else
int cnt;
#endif
#ifdef MAXLOAD
md_loadav(avec);
if (avec[1] > (MAXLOAD / 10.0))
return TRUE;
#endif
#ifdef MAXUSERS
if (ucount() > MAXUSERS)
return TRUE;
#endif
return FALSE;
}
/*
* author:
* See if a user is an author of the program
*/
bool
author()
{
#ifdef MASTER
if (wizard)
return TRUE;
#endif
switch (md_getuid())
{
case -1:
return TRUE;
default:
return FALSE;
}
}
#endif
#ifdef CHECKTIME
/*
* checkout:
* Check each CHECKTIME seconds to see if the load is too high
*/
checkout(struct rogue_state *rs,int sig)
{
static char *msgs[] = {
"The load is too high to be playing. Please leave in %0.1f minutes",
"Please save your game. You have %0.1f minutes",
"Last warning. You have %0.1f minutes to leave",
};
int checktime;
if (too_much())
{
if (author())
{
num_checks = 1;
chmsg(rs,"The load is rather high, O exaulted one");
}
else if (num_checks++ == 3)
fatal("Sorry. You took too long. You are dead\n");
checktime = (CHECKTIME * 60) / num_checks;
chmsg(rs,msgs[num_checks - 1], ((double) checktime / 60.0));
}
else
{
if (num_checks)
{
num_checks = 0;
chmsg(rs,"The load has dropped back down. You have a reprieve");
}
checktime = (CHECKTIME * 60);
}
md_start_checkout_timer(checktime);
}
/*
* chmsg:
* checkout()'s version of msg. If we are in the middle of a
* shell, do a printf instead of a msg to a the refresh.
*/
/* VARARGS1 */
chmsg(struct rogue_state *rs,char *fmt, int arg)
{
if (!in_shell)
msg(rs,fmt, arg);
else
{
printf(fmt, arg);
putchar('\n');
fflush(stdout);
}
}
#endif
#ifdef UCOUNT
/*
* ucount:
* count number of users on the system
*/
#include <utmp.h>
struct utmp buf;
int
ucount()
{
struct utmp *up;
FILE *utmp;
int count;
if ((utmp = fopen(UTMP, "r")) == NULL)
return 0;
up = &buf;
count = 0;
while (fread(up, 1, sizeof (*up), utmp) > 0)
if (buf.ut_name[0] != '\0')
count++;
fclose(utmp);
return count;
}
#endif
/*
* lock_sc:
* lock the score file. If it takes too long, ask the user if
* they care to wait. Return TRUE if the lock is successful.
*/
static FILE *lfd = NULL;
bool
lock_sc()
{
#if defined(SCOREFILE) && defined(LOCKFILE)
int cnt;
static struct stat sbuf;
char *lockfile = LOCKFILE;
over:
if ((lfd=fopen(lockfile, "w+")) != NULL)
return TRUE;
for (cnt = 0; cnt < 5; cnt++)
{
md_sleep(1);
if ((lfd=fopen(lockfile, "w+")) != NULL)
return TRUE;
}
if (stat(lockfile, &sbuf) < 0)
{
lfd=fopen(lockfile, "w+");
return TRUE;
}
if (time(NULL) - sbuf.st_mtime > 10)
{
if (md_unlink(lockfile) < 0)
return FALSE;
goto over;
}
else
{
printf("The score file is very busy. Do you want to wait longer\n");
printf("for it to become free so your score can get posted?\n");
printf("If so, type \"y\"\n");
if (fgets(prbuf, MAXSTR, stdin) != 0 )
;
if (prbuf[0] == 'y')
for (;;)
{
if ((lfd=fopen(lockfile, "w+")) != 0)
return TRUE;
if (stat(lockfile, &sbuf) < 0)
{
lfd=fopen(lockfile, "w+");
return TRUE;
}
if (time(NULL) - sbuf.st_mtime > 10)
{
if (md_unlink(lockfile) < 0)
return FALSE;
}
md_sleep(1);
}
else
return FALSE;
}
#else
return TRUE;
#endif
}
/*
* unlock_sc:
* Unlock the score file
*/
void
unlock_sc()
{
#if defined(SCOREFILE) && defined(LOCKFILE)
if (lfd != NULL)
fclose(lfd);
lfd = NULL;
md_unlink(LOCKFILE);
#endif
}
/*
* flush_type:
* Flush typeahead for traps, etc.
*/
void
flush_type()
{
flushinp();
}

266
src/cc/rogue/main.c Normal file
View File

@@ -0,0 +1,266 @@
/******************************************************************************
* Copyright © 2014-2019 The SuperNET Developers. *
* *
* See the AUTHORS, DEVELOPER-AGREEMENT and LICENSE files at *
* the top-level directory of this distribution for the individual copyright *
* holder information and the developer policies on copyright and licensing. *
* *
* Unless otherwise agreed in a custom licensing agreement, no part of the *
* SuperNET software, including this file may be copied, modified, propagated *
* or distributed except according to the terms contained in the LICENSE file *
* *
* Removal or modification of this copyright notice is prohibited. *
* *
******************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <unistd.h>
#define SMALLVAL 0.000000000000001
#define SATOSHIDEN ((uint64_t)100000000L)
#define dstr(x) ((double)(x) / SATOSHIDEN)
#ifndef _BITS256
#define _BITS256
union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; };
typedef union _bits256 bits256;
#endif
int32_t _unhex(char c)
{
if ( c >= '0' && c <= '9' )
return(c - '0');
else if ( c >= 'a' && c <= 'f' )
return(c - 'a' + 10);
else if ( c >= 'A' && c <= 'F' )
return(c - 'A' + 10);
return(-1);
}
int32_t is_hexstr(char *str,int32_t n)
{
int32_t i;
if ( str == 0 || str[0] == 0 )
return(0);
for (i=0; str[i]!=0; i++)
{
if ( n > 0 && i >= n )
break;
if ( _unhex(str[i]) < 0 )
break;
}
if ( n == 0 )
return(i);
return(i == n);
}
int32_t unhex(char c)
{
int32_t hex;
if ( (hex= _unhex(c)) < 0 )
{
//printf("unhex: illegal hexchar.(%c)\n",c);
}
return(hex);
}
unsigned char _decode_hex(char *hex) { return((unhex(hex[0])<<4) | unhex(hex[1])); }
int32_t decode_hex(uint8_t *bytes,int32_t n,char *hex)
{
int32_t adjust,i = 0;
//printf("decode.(%s)\n",hex);
if ( is_hexstr(hex,n) <= 0 )
{
memset(bytes,0,n);
return(n);
}
if ( hex[n-1] == '\n' || hex[n-1] == '\r' )
hex[--n] = 0;
if ( n == 0 || (hex[n*2+1] == 0 && hex[n*2] != 0) )
{
if ( n > 0 )
{
bytes[0] = unhex(hex[0]);
printf("decode_hex n.%d hex[0] (%c) -> %d hex.(%s) [n*2+1: %d] [n*2: %d %c] len.%ld\n",n,hex[0],bytes[0],hex,hex[n*2+1],hex[n*2],hex[n*2],(long)strlen(hex));
}
bytes++;
hex++;
adjust = 1;
} else adjust = 0;
if ( n > 0 )
{
for (i=0; i<n; i++)
bytes[i] = _decode_hex(&hex[i*2]);
}
//bytes[i] = 0;
return(n + adjust);
}
char hexbyte(int32_t c)
{
c &= 0xf;
if ( c < 10 )
return('0'+c);
else if ( c < 16 )
return('a'+c-10);
else return(0);
}
int32_t init_hexbytes_noT(char *hexbytes,unsigned char *message,long len)
{
int32_t i;
if ( len <= 0 )
{
hexbytes[0] = 0;
return(1);
}
for (i=0; i<len; i++)
{
hexbytes[i*2] = hexbyte((message[i]>>4) & 0xf);
hexbytes[i*2 + 1] = hexbyte(message[i] & 0xf);
//printf("i.%d (%02x) [%c%c]\n",i,message[i],hexbytes[i*2],hexbytes[i*2+1]);
}
hexbytes[len*2] = 0;
//printf("len.%ld\n",len*2+1);
return((int32_t)len*2+1);
}
char *bits256_str(char hexstr[65],bits256 x)
{
init_hexbytes_noT(hexstr,x.bytes,sizeof(x));
return(hexstr);
}
long _stripwhite(char *buf,int accept)
{
int32_t i,j,c;
if ( buf == 0 || buf[0] == 0 )
return(0);
for (i=j=0; buf[i]!=0; i++)
{
buf[j] = c = buf[i];
if ( c == accept || (c != ' ' && c != '\n' && c != '\r' && c != '\t' && c != '\b') )
j++;
}
buf[j] = 0;
return(j);
}
char *clonestr(char *str)
{
char *clone;
if ( str == 0 || str[0] == 0 )
{
printf("warning cloning nullstr.%p\n",str);
#ifdef __APPLE__
while ( 1 ) sleep(1);
#endif
str = (char *)"<nullstr>";
}
clone = (char *)malloc(strlen(str)+16);
strcpy(clone,str);
return(clone);
}
int32_t safecopy(char *dest,char *src,long len)
{
int32_t i = -1;
if ( src != 0 && dest != 0 && src != dest )
{
if ( dest != 0 )
memset(dest,0,len);
for (i=0; i<len&&src[i]!=0; i++)
dest[i] = src[i];
if ( i == len )
{
printf("safecopy: %s too long %ld\n",src,len);
#ifdef __APPLE__
//getchar();
#endif
return(-1);
}
dest[i] = 0;
}
return(i);
}
#define true 1
#define false 0
#ifdef STANDALONE
#include "../komodo/src/komodo_cJSON.c"
#else
#include "../../komodo_cJSON.c"
#endif
int32_t rogue_replay(uint64_t seed,int32_t sleeptime);
int rogue(int argc, char **argv, char **envp);
void *OS_loadfile(char *fname,uint8_t **bufp,long *lenp,long *allocsizep)
{
FILE *fp;
long filesize,buflen = *allocsizep;
uint8_t *buf = *bufp;
*lenp = 0;
if ( (fp= fopen(fname,"rb")) != 0 )
{
fseek(fp,0,SEEK_END);
filesize = ftell(fp);
if ( filesize == 0 )
{
fclose(fp);
*lenp = 0;
printf("OS_loadfile null size.(%s)\n",fname);
return(0);
}
if ( filesize > buflen )
{
*allocsizep = filesize;
*bufp = buf = (uint8_t *)realloc(buf,(long)*allocsizep+64);
}
rewind(fp);
if ( buf == 0 )
printf("Null buf ???\n");
else
{
if ( fread(buf,1,(long)filesize,fp) != (unsigned long)filesize )
printf("error reading filesize.%ld\n",(long)filesize);
buf[filesize] = 0;
}
fclose(fp);
*lenp = filesize;
//printf("loaded.(%s)\n",buf);
} //else printf("OS_loadfile couldnt load.(%s)\n",fname);
return(buf);
}
uint8_t *OS_fileptr(long *allocsizep,char *fname)
{
long filesize = 0; uint8_t *buf = 0; void *retptr;
*allocsizep = 0;
retptr = OS_loadfile(fname,&buf,&filesize,allocsizep);
return((uint8_t *)retptr);
}
int main(int argc, char **argv, char **envp)
{
uint64_t seed; FILE *fp = 0;
if ( argc == 2 && (fp=fopen(argv[1],"rb")) == 0 )
{
seed = atol(argv[1]);
//fprintf(stderr,"replay %llu\n",(long long)seed);
return(rogue_replay(seed,50000));
}
else
{
if ( fp != 0 )
fclose(fp);
return(rogue(argc,argv,envp));
}
}

1432
src/cc/rogue/mdport.c Normal file

File diff suppressed because it is too large Load Diff

598
src/cc/rogue/misc.c Normal file
View File

@@ -0,0 +1,598 @@
/*
* All sorts of miscellaneous routines
*
* @(#)misc.c 4.66 (Berkeley) 08/06/83
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <stdlib.h>
//#include <curses.h>
//#include <string.h>
//#include <ctype.h>
#include "rogue.h"
/*
* look:
* A quick glance all around the player
*/
#undef DEBUG
void
look(struct rogue_state *rs,bool wakeup)
{
int x, y;
int ch;
THING *tp;
PLACE *pp;
struct room *rp;
int ey, ex;
int passcount;
char pfl, *fp, pch;
int sy, sx, sumhero = 0, diffhero = 0;
# ifdef DEBUG
static bool done = FALSE;
if (done)
return;
done = TRUE;
# endif /* DEBUG */
passcount = 0;
rp = proom;
if (!ce(oldpos, hero))
{
erase_lamp(&oldpos, oldrp);
oldpos = hero;
oldrp = rp;
}
ey = hero.y + 1;
ex = hero.x + 1;
sx = hero.x - 1;
sy = hero.y - 1;
if (door_stop && !firstmove && running)
{
sumhero = hero.y + hero.x;
diffhero = hero.y - hero.x;
}
pp = INDEX(hero.y, hero.x);
pch = pp->p_ch;
pfl = pp->p_flags;
for (y = sy; y <= ey; y++)
if (y > 0 && y < NUMLINES - 1) for (x = sx; x <= ex; x++)
{
if (x < 0 || x >= NUMCOLS)
continue;
if (!on(player, ISBLIND))
{
if (y == hero.y && x == hero.x)
continue;
}
pp = INDEX(y, x);
ch = pp->p_ch;
if (ch == ' ') /* nothing need be done with a ' ' */
continue;
fp = &pp->p_flags;
if (pch != DOOR && ch != DOOR)
if ((pfl & F_PASS) != (*fp & F_PASS))
continue;
if (((*fp & F_PASS) || ch == DOOR) &&
((pfl & F_PASS) || pch == DOOR))
{
if (hero.x != x && hero.y != y &&
!step_ok(chat(y, hero.x)) && !step_ok(chat(hero.y, x)))
continue;
}
if ((tp = pp->p_monst) == NULL)
ch = trip_ch(y, x, ch);
else
if (on(player, SEEMONST) && on(*tp, ISINVIS))
{
if (door_stop && !firstmove)
running = FALSE;
continue;
}
else
{
if (wakeup)
wake_monster(rs,y, x);
if (see_monst(tp))
{
if (on(player, ISHALU))
ch = rnd(26) + 'A';
else
ch = tp->t_disguise;
}
}
if (on(player, ISBLIND) && (y != hero.y || x != hero.x))
continue;
move(y, x);
if ((proom->r_flags & ISDARK) && !see_floor && ch == FLOOR)
ch = ' ';
if (tp != NULL || ch != CCHAR( inch() ))
addch(ch);
if (door_stop && !firstmove && running)
{
switch (runch)
{
case 'h':
if (x == ex)
continue;
when 'j':
if (y == sy)
continue;
when 'k':
if (y == ey)
continue;
when 'l':
if (x == sx)
continue;
when 'y':
if ((y + x) - sumhero >= 1)
continue;
when 'u':
if ((y - x) - diffhero >= 1)
continue;
when 'n':
if ((y + x) - sumhero <= -1)
continue;
when 'b':
if ((y - x) - diffhero <= -1)
continue;
}
switch (ch)
{
case DOOR:
if (x == hero.x || y == hero.y)
running = FALSE;
break;
case PASSAGE:
if (x == hero.x || y == hero.y)
passcount++;
break;
case FLOOR:
case '|':
case '-':
case ' ':
break;
default:
running = FALSE;
break;
}
}
}
if (door_stop && !firstmove && passcount > 1)
running = FALSE;
if (!running || !jump)
mvaddch(hero.y, hero.x, PLAYER);
# ifdef DEBUG
done = FALSE;
# endif /* DEBUG */
}
/*
* trip_ch:
* Return the character appropriate for this space, taking into
* account whether or not the player is tripping.
*/
int
trip_ch(int y, int x, int ch)
{
if (on(player, ISHALU) && after)
switch (ch)
{
case FLOOR:
case ' ':
case PASSAGE:
case '-':
case '|':
case DOOR:
case TRAP:
break;
default:
if (y != stairs.y || x != stairs.x || !seenstairs)
ch = rnd_thing();
break;
}
return ch;
}
/*
* erase_lamp:
* Erase the area shown by a lamp in a dark room.
*/
void
erase_lamp(coord *pos, struct room *rp)
{
int y, x, ey, sy, ex;
if (!(see_floor && (rp->r_flags & (ISGONE|ISDARK)) == ISDARK
&& !on(player,ISBLIND)))
return;
ey = pos->y + 1;
ex = pos->x + 1;
sy = pos->y - 1;
for (x = pos->x - 1; x <= ex; x++)
for (y = sy; y <= ey; y++)
{
if (y == hero.y && x == hero.x)
continue;
move(y, x);
if (inch() == FLOOR)
addch(' ');
}
}
/*
* show_floor:
* Should we show the floor in her room at this time?
*/
bool
show_floor()
{
if ((proom->r_flags & (ISGONE|ISDARK)) == ISDARK && !on(player, ISBLIND))
return see_floor;
else
return TRUE;
}
/*
* find_obj:
* Find the unclaimed object at y, x
*/
THING *
find_obj(struct rogue_state *rs,int y, int x)
{
THING *obj;
for (obj = lvl_obj; obj != NULL; obj = next(obj))
{
if (obj->o_pos.y == y && obj->o_pos.x == x)
return obj;
}
#ifdef MASTER
sprintf(prbuf, "Non-object %d,%d", y, x);
msg(rs,prbuf);
return NULL;
#else
/* NOTREACHED */
return NULL;
#endif
}
/*
* eat:
* She wants to eat something, so let her try
*/
void
eat(struct rogue_state *rs)
{
THING *obj;
if ((obj = get_item(rs,"eat", FOOD)) == NULL)
return;
if (obj->o_type != FOOD)
{
if (!terse)
msg(rs,"ugh, you would get ill if you ate that");
else
msg(rs,"that's Inedible!");
return;
}
if (food_left < 0)
food_left = 0;
if ((food_left += HUNGERTIME - 200 + rnd(400)) > STOMACHSIZE)
food_left = STOMACHSIZE;
hungry_state = 0;
if (obj == cur_weapon)
cur_weapon = NULL;
if (obj->o_which == 1)
msg(rs,"my, that was a yummy %s", fruit);
else
if (rnd(100) > 70)
{
pstats.s_exp++;
msg(rs,"%s, this food tastes awful", choose_str("bummer", "yuk"));
check_level(rs);
}
else
msg(rs,"%s, that tasted good", choose_str("oh, wow", "yum"));
leave_pack(rs,obj, FALSE, FALSE);
}
/*
* check_level:
* Check to see if the guy has gone up a level.
*/
void
check_level(struct rogue_state *rs)
{
int i, add, olevel;
for (i = 0; e_levels[i] != 0; i++)
if (e_levels[i] > pstats.s_exp)
break;
i++;
olevel = pstats.s_lvl;
pstats.s_lvl = i;
if (i > olevel)
{
add = roll(i - olevel, 10);
max_hp += add;
pstats.s_hpt += add;
msg(rs,"welcome to level %d", i);
}
}
/*
* chg_str:
* used to modify the playes strength. It keeps track of the
* highest it has been, just in case
*/
void
chg_str(int amt)
{
//auto jl777: strange compiler error
str_t comp;
if (amt == 0)
return;
add_str(&pstats.s_str, amt);
comp = pstats.s_str;
if (ISRING(LEFT, R_ADDSTR))
add_str(&comp, -cur_ring[LEFT]->o_arm);
if (ISRING(RIGHT, R_ADDSTR))
add_str(&comp, -cur_ring[RIGHT]->o_arm);
if (comp > max_stats.s_str)
max_stats.s_str = comp;
}
/*
* add_str:
* Perform the actual add, checking upper and lower bound limits
*/
void
add_str(str_t *sp, int amt)
{
if ((*sp += amt) < 3)
*sp = 3;
else if (*sp > 31)
*sp = 31;
}
/*
* add_haste:
* Add a haste to the player
*/
bool
add_haste(struct rogue_state *rs,bool potion)
{
if (on(player, ISHASTE))
{
no_command += rnd(8);
player.t_flags &= ~(ISRUN|ISHASTE);
extinguish(nohaste);
msg(rs,"you faint from exhaustion");
return FALSE;
}
else
{
player.t_flags |= ISHASTE;
if (potion)
fuse(nohaste, 0, rnd(4)+4, AFTER);
return TRUE;
}
}
/*
* aggravate:
* Aggravate all the monsters on this level
*/
void
aggravate(struct rogue_state *rs)
{
THING *mp;
for (mp = mlist; mp != NULL; mp = next(mp))
runto(rs,&mp->t_pos);
}
/*
* vowelstr:
* For printfs: if string starts with a vowel, return "n" for an
* "an".
*/
char *
vowelstr(char *str)
{
switch (*str)
{
case 'a': case 'A':
case 'e': case 'E':
case 'i': case 'I':
case 'o': case 'O':
case 'u': case 'U':
return "n";
default:
return "";
}
}
/*
* is_current:
* See if the object is one of the currently used items
*/
bool
is_current(struct rogue_state *rs,THING *obj)
{
if (obj == NULL)
return FALSE;
if (obj == cur_armor || obj == cur_weapon || obj == cur_ring[LEFT]
|| obj == cur_ring[RIGHT])
{
if (!terse)
addmsg(rs,"That's already ");
msg(rs,"in use");
return TRUE;
}
return FALSE;
}
/*
* get_dir:
* Set up the direction co_ordinate for use in varios "prefix"
* commands
*/
bool
get_dir(struct rogue_state *rs)
{
char *prompt;
bool gotit;
static coord last_delt= {0,0};
if (again && last_dir != '\0')
{
delta.y = last_delt.y;
delta.x = last_delt.x;
dir_ch = last_dir;
}
else
{
if (!terse)
msg(rs,prompt = "which direction? ");
else
prompt = "direction: ";
do
{
gotit = TRUE;
switch (dir_ch = readchar(rs))
{
case 'h': case'H': delta.y = 0; delta.x = -1;
when 'j': case'J': delta.y = 1; delta.x = 0;
when 'k': case'K': delta.y = -1; delta.x = 0;
when 'l': case'L': delta.y = 0; delta.x = 1;
when 'y': case'Y': delta.y = -1; delta.x = -1;
when 'u': case'U': delta.y = -1; delta.x = 1;
when 'b': case'B': delta.y = 1; delta.x = -1;
when 'n': case'N': delta.y = 1; delta.x = 1;
when ESCAPE: last_dir = '\0'; reset_last(); return FALSE;
otherwise:
mpos = 0;
msg(rs,prompt);
gotit = FALSE;
}
} until (gotit);
if (isupper(dir_ch))
dir_ch = (char) tolower(dir_ch);
last_dir = dir_ch;
last_delt.y = delta.y;
last_delt.x = delta.x;
}
if (on(player, ISHUH) && rnd(5) == 0)
do
{
delta.y = rnd(3) - 1;
delta.x = rnd(3) - 1;
} while (delta.y == 0 && delta.x == 0);
mpos = 0;
return TRUE;
}
/*
* sign:
* Return the sign of the number
*/
int
sign(int nm)
{
if (nm < 0)
return -1;
else
return (nm > 0);
}
/*
* spread:
* Give a spread around a given number (+/- 20%)
*/
int
spread(int nm)
{
return nm - nm / 20 + rnd(nm / 10);
}
/*
* call_it:
* Call an object something after use.
*/
void
call_it(struct rogue_state *rs,struct obj_info *info)
{
if (info->oi_know)
{
if (info->oi_guess)
{
free(info->oi_guess);
info->oi_guess = NULL;
}
}
else if (!info->oi_guess)
{
msg(rs,terse ? (char *)"call it: " : (char *)"what do you want to call it? ");
if (get_str(rs,prbuf, stdscr) == NORM)
{
if (info->oi_guess != NULL)
free(info->oi_guess);
info->oi_guess = (char *)malloc((unsigned int) strlen(prbuf) + 1);
strcpy(info->oi_guess, prbuf);
}
}
}
/*
* rnd_thing:
* Pick a random thing appropriate for this level
*/
char
rnd_thing()
{
int i;
static char thing_list[] = {
POTION, SCROLL, RING, STICK, FOOD, WEAPON, ARMOR, STAIRS, GOLD, AMULET
};
if (level >= AMULETLEVEL)
i = rnd(sizeof thing_list / sizeof (char));
else
i = rnd(sizeof thing_list / sizeof (char) - 1);
return thing_list[i];
}
/*
str str:
* Choose the first or second string depending on whether it the
* player is tripping
*/
char *
choose_str(char *ts, char *ns)
{
return (on(player, ISHALU) ? ts : ns);
}

255
src/cc/rogue/monsters.c Normal file
View File

@@ -0,0 +1,255 @@
/*
* File with various monster functions in it
*
* @(#)monsters.c 4.46 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <curses.h>
//#include <string.h>
#include "rogue.h"
//#include <ctype.h>
/*
* List of monsters in rough order of vorpalness
*/
static char lvl_mons[] = {
'K', 'E', 'B', 'S', 'H', 'I', 'R', 'O', 'Z', 'L', 'C', 'Q', 'A',
'N', 'Y', 'F', 'T', 'W', 'P', 'X', 'U', 'M', 'V', 'G', 'J', 'D'
};
static char wand_mons[] = {
'K', 'E', 'B', 'S', 'H', 0, 'R', 'O', 'Z', 0, 'C', 'Q', 'A',
0, 'Y', 0, 'T', 'W', 'P', 0, 'U', 'M', 'V', 'G', 'J', 0
};
/*
* randmonster:
* Pick a monster to show up. The lower the level,
* the meaner the monster.
*/
char
randmonster(bool wander)
{
int d;
char *mons;
mons = (wander ? wand_mons : lvl_mons);
do
{
d = level + (rnd(10) - 6);
if (d < 0)
d = rnd(5);
if (d > 25)
d = rnd(5) + 21;
} while (mons[d] == 0);
return mons[d];
}
/*
* new_monster:
* Pick a new monster and add it to the list
*/
void
new_monster(struct rogue_state *rs,THING *tp, char type, coord *cp)
{
struct monster *mp;
int lev_add;
if ((lev_add = level - AMULETLEVEL) < 0)
lev_add = 0;
attach(mlist, tp);
tp->t_type = type;
tp->t_disguise = type;
tp->t_pos = *cp;
move(cp->y, cp->x);
tp->t_oldch = CCHAR( inch() );
tp->t_room = roomin(rs,cp);
moat(cp->y, cp->x) = tp;
mp = &monsters[tp->t_type-'A'];
tp->t_stats.s_lvl = mp->m_stats.s_lvl + lev_add;
tp->t_stats.s_maxhp = tp->t_stats.s_hpt = roll(tp->t_stats.s_lvl, 8);
tp->t_stats.s_arm = mp->m_stats.s_arm - lev_add;
strcpy(tp->t_stats.s_dmg,mp->m_stats.s_dmg);
tp->t_stats.s_str = mp->m_stats.s_str;
tp->t_stats.s_exp = mp->m_stats.s_exp + lev_add * 10 + exp_add(tp);
tp->t_flags = mp->m_flags;
if (level > 29)
tp->t_flags |= ISHASTE;
tp->t_turn = TRUE;
tp->t_pack = NULL;
if (ISWEARING(R_AGGR))
runto(rs,cp);
if (type == 'X')
tp->t_disguise = rnd_thing();
}
/*
* expadd:
* Experience to add for this monster's level/hit points
*/
int
exp_add(THING *tp)
{
int mod;
if (tp->t_stats.s_lvl == 1)
mod = tp->t_stats.s_maxhp / 8;
else
mod = tp->t_stats.s_maxhp / 6;
if (tp->t_stats.s_lvl > 9)
mod *= 20;
else if (tp->t_stats.s_lvl > 6)
mod *= 4;
return mod;
}
/*
* wanderer:
* Create a new wandering monster and aim it at the player
*/
void
wanderer(struct rogue_state *rs)
{
THING *tp;
static coord cp;
tp = new_item();
do
{
find_floor((struct room *) NULL, &cp, FALSE, TRUE);
} while (roomin(rs,&cp) == proom);
new_monster(rs,tp, randmonster(TRUE), &cp);
if (on(player, SEEMONST))
{
standout();
if (!on(player, ISHALU))
addch(tp->t_type);
else
addch(rnd(26) + 'A');
standend();
}
runto(rs,&tp->t_pos);
#ifdef MASTER
if (wizard)
msg(rs,"started a wandering %s", monsters[tp->t_type-'A'].m_name);
#endif
}
/*
* wake_monster:
* What to do when the hero steps next to a monster
*/
THING *
wake_monster(struct rogue_state *rs,int y, int x)
{
THING *tp;
struct room *rp;
char ch, *mname;
#ifdef MASTER
if ((tp = moat(y, x)) == NULL)
msg(rs,"can't find monster in wake_monster");
#else
tp = moat(y, x);
if (tp == NULL)
endwin(), abort();
#endif
ch = tp->t_type;
/*
* Every time he sees mean monster, it might start chasing him
*/
if (!on(*tp, ISRUN) && rnd(3) != 0 && on(*tp, ISMEAN) && !on(*tp, ISHELD)
&& !ISWEARING(R_STEALTH) && !on(player, ISLEVIT))
{
tp->t_dest = &hero;
tp->t_flags |= ISRUN;
}
if (ch == 'M' && !on(player, ISBLIND) && !on(player, ISHALU)
&& !on(*tp, ISFOUND) && !on(*tp, ISCANC) && on(*tp, ISRUN))
{
rp = proom;
if ((rp != NULL && !(rp->r_flags & ISDARK))
|| dist(y, x, hero.y, hero.x) < LAMPDIST)
{
tp->t_flags |= ISFOUND;
if (!save(VS_MAGIC))
{
if (on(player, ISHUH))
lengthen(unconfuse, spread(HUHDURATION));
else
fuse(unconfuse, 0, spread(HUHDURATION), AFTER);
player.t_flags |= ISHUH;
mname = set_mname(tp);
addmsg(rs,"%s", mname);
if (strcmp(mname, "it") != 0)
addmsg(rs,"'");
msg(rs,"s gaze has confused you");
}
}
}
/*
* Let greedy ones guard gold
*/
if (on(*tp, ISGREED) && !on(*tp, ISRUN))
{
tp->t_flags |= ISRUN;
if (proom->r_goldval)
tp->t_dest = &proom->r_gold;
else
tp->t_dest = &hero;
}
return tp;
}
/*
* give_pack:
* Give a pack to a monster if it deserves one
*/
void
give_pack(struct rogue_state *rs,THING *tp)
{
if (level >= max_level && rnd(100) < monsters[tp->t_type-'A'].m_carry)
{
//fprintf(stderr,"give_pack\n");
attach(tp->t_pack, new_thing(rs));
}
}
/*
* save_throw:
* See if a creature save against something
*/
int
save_throw(int which, THING *tp)
{
int need;
need = 14 + which - tp->t_stats.s_lvl / 2;
return (roll(1, 20) >= need);
}
/*
* save:
* See if he saves against various nasty things
*/
int
save(int which)
{
if (which == VS_MAGIC)
{
if (ISRING(LEFT, R_PROTECT))
which -= cur_ring[LEFT]->o_arm;
if (ISRING(RIGHT, R_PROTECT))
which -= cur_ring[RIGHT]->o_arm;
}
return save_throw(which, &player);
}

426
src/cc/rogue/move.c Normal file
View File

@@ -0,0 +1,426 @@
/*
* hero movement commands
*
* @(#)move.c 4.49 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <curses.h>
//#include <ctype.h>
#include "rogue.h"
/*
* used to hold the new hero position
*/
coord nh;
/*
* do_run:
* Start the hero running
*/
void
do_run(char ch)
{
running = TRUE;
after = FALSE;
runch = ch;
}
/*
* do_move:
* Check to see that a move is legal. If it is handle the
* consequences (fighting, picking up, etc.)
*/
void
do_move(struct rogue_state *rs,int dy, int dx)
{
char ch, fl;
firstmove = FALSE;
if (no_move)
{
no_move--;
msg(rs,"you are still stuck in the bear trap");
return;
}
/*
* Do a confused move (maybe)
*/
if (on(player, ISHUH) && rnd(5) != 0)
{
nh = *rndmove(&player);
if (ce(nh, hero))
{
after = FALSE;
running = FALSE;
to_death = FALSE;
return;
}
}
else
{
over:
nh.y = hero.y + dy;
nh.x = hero.x + dx;
}
/*
* Check if he tried to move off the screen or make an illegal
* diagonal move, and stop him if he did.
*/
if (nh.x < 0 || nh.x >= NUMCOLS || nh.y <= 0 || nh.y >= NUMLINES - 1)
goto hit_bound;
if (!diag_ok(&hero, &nh))
{
after = FALSE;
running = FALSE;
return;
}
if (running && ce(hero, nh))
after = running = FALSE;
fl = flat(nh.y, nh.x);
ch = winat(nh.y, nh.x);
if (!(fl & F_REAL) && ch == FLOOR)
{
if (!on(player, ISLEVIT))
{
chat(nh.y, nh.x) = ch = TRAP;
flat(nh.y, nh.x) |= F_REAL;
}
}
else if (on(player, ISHELD) && ch != 'F')
{
msg(rs,"you are being held");
return;
}
switch (ch)
{
case ' ':
case '|':
case '-':
hit_bound:
if (passgo && running && (proom->r_flags & ISGONE)
&& !on(player, ISBLIND))
{
bool b1, b2;
switch (runch)
{
case 'h':
case 'l':
b1 = (bool)(hero.y != 1 && turn_ok(hero.y - 1, hero.x));
b2 = (bool)(hero.y != NUMLINES - 2 && turn_ok(hero.y + 1, hero.x));
if (!(b1 ^ b2))
break;
if (b1)
{
runch = 'k';
dy = -1;
}
else
{
runch = 'j';
dy = 1;
}
dx = 0;
turnref();
goto over;
case 'j':
case 'k':
b1 = (bool)(hero.x != 0 && turn_ok(hero.y, hero.x - 1));
b2 = (bool)(hero.x != NUMCOLS - 1 && turn_ok(hero.y, hero.x + 1));
if (!(b1 ^ b2))
break;
if (b1)
{
runch = 'h';
dx = -1;
}
else
{
runch = 'l';
dx = 1;
}
dy = 0;
turnref();
goto over;
}
}
running = FALSE;
after = FALSE;
break;
case DOOR:
running = FALSE;
if (flat(hero.y, hero.x) & F_PASS)
enter_room(rs,&nh);
goto move_stuff;
case TRAP:
ch = be_trapped(rs,&nh);
if (ch == T_DOOR || ch == T_TELEP)
return;
goto move_stuff;
case PASSAGE:
/*
* when you're in a corridor, you don't know if you're in
* a maze room or not, and there ain't no way to find out
* if you're leaving a maze room, so it is necessary to
* always recalculate proom.
*/
proom = roomin(rs,&hero);
goto move_stuff;
case FLOOR:
if (!(fl & F_REAL))
be_trapped(rs,&hero);
goto move_stuff;
case STAIRS:
seenstairs = TRUE;
/* FALLTHROUGH */
default:
running = FALSE;
if (isupper(ch) || moat(nh.y, nh.x))
fight(rs,&nh, cur_weapon, FALSE);
else
{
if (ch != STAIRS)
take = ch;
move_stuff:
mvaddch(hero.y, hero.x, floor_at());
if ((fl & F_PASS) && chat(oldpos.y, oldpos.x) == DOOR)
leave_room(rs,&nh);
hero = nh;
}
}
}
/*
* turn_ok:
* Decide whether it is legal to turn onto the given space
*/
bool
turn_ok(int y, int x)
{
PLACE *pp;
pp = INDEX(y, x);
return (pp->p_ch == DOOR
|| (pp->p_flags & (F_REAL|F_PASS)) == (F_REAL|F_PASS));
}
/*
* turnref:
* Decide whether to refresh at a passage turning or not
*/
void
turnref()
{
PLACE *pp;
pp = INDEX(hero.y, hero.x);
if (!(pp->p_flags & F_SEEN))
{
if (jump)
{
leaveok(stdscr, TRUE);
if ( globalR.sleeptime != 0 )
refresh();
leaveok(stdscr, FALSE);
}
pp->p_flags |= F_SEEN;
}
}
/*
* door_open:
* Called to illuminate a room. If it is dark, remove anything
* that might move.
*/
void
door_open(struct rogue_state *rs,struct room *rp)
{
int y, x;
if (!(rp->r_flags & ISGONE))
for (y = rp->r_pos.y; y < rp->r_pos.y + rp->r_max.y; y++)
for (x = rp->r_pos.x; x < rp->r_pos.x + rp->r_max.x; x++)
if (isupper(winat(y, x)))
wake_monster(rs,y, x);
}
/*
* be_trapped:
* The guy stepped on a trap.... Make him pay.
*/
char
be_trapped(struct rogue_state *rs,coord *tc)
{
PLACE *pp;
THING *arrow;
char tr;
if (on(player, ISLEVIT))
return T_RUST; /* anything that's not a door or teleport */
running = FALSE;
count = FALSE;
pp = INDEX(tc->y, tc->x);
pp->p_ch = TRAP;
tr = pp->p_flags & F_TMASK;
pp->p_flags |= F_SEEN;
switch (tr)
{
case T_DOOR:
level++;
new_level(rs);
msg(rs,"you fell into a trap!");
when T_BEAR:
no_move += BEARTIME;
msg(rs,"you are caught in a bear trap");
when T_MYST:
switch(rnd(11))
{
case 0: msg(rs,"you are suddenly in a parallel dimension");
when 1: msg(rs,"the light in here suddenly seems %s", rainbow[rnd(cNCOLORS)]);
when 2: msg(rs,"you feel a sting in the side of your neck");
when 3: msg(rs,"multi-colored lines swirl around you, then fade");
when 4: msg(rs,"a %s light flashes in your eyes", rainbow[rnd(cNCOLORS)]);
when 5: msg(rs,"a spike shoots past your ear!");
when 6: msg(rs,"%s sparks dance across your armor", rainbow[rnd(cNCOLORS)]);
when 7: msg(rs,"you suddenly feel very thirsty");
when 8: msg(rs,"you feel time speed up suddenly");
when 9: msg(rs,"time now seems to be going slower");
when 10: msg(rs,"you pack turns %s!", rainbow[rnd(cNCOLORS)]);
}
when T_SLEEP:
no_command += SLEEPTIME;
player.t_flags &= ~ISRUN;
msg(rs,"a strange white mist envelops you and you fall asleep");
when T_ARROW:
if (swing(pstats.s_lvl - 1, pstats.s_arm, 1))
{
pstats.s_hpt -= roll(1, 6);
if (pstats.s_hpt <= 0)
{
msg(rs,"an arrow killed you");
death(rs,'a');
}
else
msg(rs,"oh no! An arrow shot you");
}
else
{
arrow = new_item();
init_weapon(arrow, ARROW);
arrow->o_count = 1;
arrow->o_pos = hero;
fall(rs,arrow, FALSE);
msg(rs,"an arrow shoots past you");
}
when T_TELEP:
/*
* since the hero's leaving, look() won't put a TRAP
* down for us, so we have to do it ourself
*/
teleport(rs);
mvaddch(tc->y, tc->x, TRAP);
when T_DART:
if (!swing(pstats.s_lvl+1, pstats.s_arm, 1))
msg(rs,"a small dart whizzes by your ear and vanishes");
else
{
pstats.s_hpt -= roll(1, 4);
if (pstats.s_hpt <= 0)
{
msg(rs,"a poisoned dart killed you");
death(rs,'d');
}
if (!ISWEARING(R_SUSTSTR) && !save(VS_POISON))
chg_str(-1);
msg(rs,"a small dart just hit you in the shoulder");
}
when T_RUST:
msg(rs,"a gush of water hits you on the head");
rust_armor(rs,cur_armor);
}
flush_type();
return tr;
}
/*
* rndmove:
* Move in a random direction if the monster/person is confused
*/
coord *
rndmove(THING *who)
{
THING *obj;
int x, y;
char ch;
static coord ret; /* what we will be returning */
y = ret.y = who->t_pos.y + rnd(3) - 1;
x = ret.x = who->t_pos.x + rnd(3) - 1;
/*
* Now check to see if that's a legal move. If not, don't move.
* (I.e., bump into the wall or whatever)
*/
if (y == who->t_pos.y && x == who->t_pos.x)
return &ret;
if (!diag_ok(&who->t_pos, &ret))
goto bad;
else
{
ch = winat(y, x);
if (!step_ok(ch))
goto bad;
if (ch == SCROLL)
{
for (obj = lvl_obj; obj != NULL; obj = next(obj))
if (y == obj->o_pos.y && x == obj->o_pos.x)
break;
if (obj != NULL && obj->o_which == S_SCARE)
goto bad;
}
}
return &ret;
bad:
ret = who->t_pos;
return &ret;
}
/*
* rust_armor:
* Rust the given armor, if it is a legal kind to rust, and we
* aren't wearing a magic ring.
*/
void
rust_armor(struct rogue_state *rs,THING *arm)
{
if (arm == NULL || arm->o_type != ARMOR || arm->o_which == LEATHER ||
arm->o_arm >= 9)
return;
if ((arm->o_flags & ISPROT) || ISWEARING(R_SUSTARM))
{
if (!to_death)
msg(rs,"the rust vanishes instantly");
}
else
{
arm->o_arm++;
if (!terse)
msg(rs,"your armor appears to be weaker now. Oh my!");
else
msg(rs,"your armor weakens");
}
}

234
src/cc/rogue/new_level.c Normal file
View File

@@ -0,0 +1,234 @@
/*
* new_level:
* Dig and draw a new level
*
* @(#)new_level.c 4.38 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <curses.h>
//#include <string.h>
#include "rogue.h"
#define TREAS_ROOM 20 /* one chance in TREAS_ROOM for a treasure room */
#define MAXTREAS 10 /* maximum number of treasures in a treasure room */
#define MINTREAS 2 /* minimum number of treasures in a treasure room */
void
new_level(struct rogue_state *rs)
{
THING *tp;
PLACE *pp;
char *sp;
int i;
player.t_flags &= ~ISHELD; /* unhold when you go down just in case */
if (level > max_level)
max_level = level;
/*
* Clean things off from last level
*/
for (pp = places; pp < &places[MAXCOLS*MAXLINES]; pp++)
{
pp->p_ch = ' ';
pp->p_flags = F_REAL;
pp->p_monst = NULL;
}
clear();
/*
* Free up the monsters on the last level
*/
for (tp = mlist; tp != NULL; tp = next(tp))
free_list(tp->t_pack);
free_list(mlist);
/*
* Throw away stuff left on the previous level (if anything)
*/
free_list(lvl_obj);
do_rooms(rs); /* Draw rooms */
do_passages(rs); /* Draw passages */
no_food++;
//fprintf(stderr,"new_level.%d\n",level);
put_things(rs); /* Place objects (if any) */
/*
* Place the traps
*/
if (rnd(10) < level)
{
ntraps = rnd(level / 4) + 1;
if (ntraps > MAXTRAPS)
ntraps = MAXTRAPS;
i = ntraps;
while (i--)
{
/*
* not only wouldn't it be NICE to have traps in mazes
* (not that we care about being nice), since the trap
* number is stored where the passage number is, we
* can't actually do it.
*/
do
{
find_floor((struct room *) NULL, &stairs, FALSE, FALSE);
} while (chat(stairs.y, stairs.x) != FLOOR);
sp = &flat(stairs.y, stairs.x);
*sp &= ~F_REAL;
*sp |= rnd(NTRAPS);
}
}
/*
* Place the staircase down.
*/
find_floor((struct room *) NULL, &stairs, FALSE, FALSE);
chat(stairs.y, stairs.x) = STAIRS;
seenstairs = FALSE;
for (tp = mlist; tp != NULL; tp = next(tp))
tp->t_room = roomin(rs,&tp->t_pos);
find_floor((struct room *) NULL, &hero, FALSE, TRUE);
enter_room(rs,&hero);
mvaddch(hero.y, hero.x, PLAYER);
if (on(player, SEEMONST))
turn_see(FALSE);
if (on(player, ISHALU))
visuals(rs,0);
}
/*
* rnd_room:
* Pick a room that is really there
*/
int
rnd_room()
{
int rm;
do
{
rm = rnd(MAXROOMS);
} while (rooms[rm].r_flags & ISGONE);
return rm;
}
/*
* put_things:
* Put potions and scrolls on this level
*/
void
put_things(struct rogue_state *rs)
{
int i;
THING *obj;
/*
* Once you have found the amulet, the only way to get new stuff is
* go down into the dungeon.
*/
if (amulet && level < max_level)
return;
/*
* check for treasure rooms, and if so, put it in.
*/
if (rnd(TREAS_ROOM) == 0)
treas_room(rs);
/*
* Do MAXOBJ attempts to put things on a level
*/
for (i = 0; i < MAXOBJ; i++)
if (rnd(100) < 36)
{
/*
* Pick a new object and link it in the list
*/
obj = new_thing(rs);
//fprintf(stderr,"put_things i.%d obj.%p\n",i,obj);
attach(lvl_obj, obj);
/*
* Put it somewhere
*/
find_floor((struct room *) NULL, &obj->o_pos, FALSE, FALSE);
chat(obj->o_pos.y, obj->o_pos.x) = (char) obj->o_type;
}
/*
* If he is really deep in the dungeon and he hasn't found the
* amulet yet, put it somewhere on the ground
*/
if (level >= AMULETLEVEL && !amulet)
{
obj = new_item();
attach(lvl_obj, obj);
obj->o_hplus = 0;
obj->o_dplus = 0;
strncpy(obj->o_damage,"0x0",sizeof(obj->o_damage));
strncpy(obj->o_hurldmg,"0x0",sizeof(obj->o_hurldmg));
obj->o_arm = 11;
obj->o_type = AMULET;
/*
* Put it somewhere
*/
find_floor((struct room *) NULL, &obj->o_pos, FALSE, FALSE);
chat(obj->o_pos.y, obj->o_pos.x) = AMULET;
}
}
/*
* treas_room:
* Add a treasure room
*/
#define MAXTRIES 10 /* max number of tries to put down a monster */
void
treas_room(struct rogue_state *rs)
{
int nm;
THING *tp;
struct room *rp;
int spots, num_monst;
static coord mp;
rp = &rooms[rnd_room()];
spots = (rp->r_max.y - 2) * (rp->r_max.x - 2) - MINTREAS;
if (spots > (MAXTREAS - MINTREAS))
spots = (MAXTREAS - MINTREAS);
num_monst = nm = rnd(spots) + MINTREAS;
while (nm--)
{
find_floor(rp, &mp, 2 * MAXTRIES, FALSE);
//fprintf(stderr,"treas_room\n");
tp = new_thing(rs);
tp->o_pos = mp;
attach(lvl_obj, tp);
chat(mp.y, mp.x) = (char) tp->o_type;
}
/*
* fill up room with monsters from the next level down
*/
if ((nm = rnd(spots) + MINTREAS) < num_monst + 2)
nm = num_monst + 2;
spots = (rp->r_max.y - 2) * (rp->r_max.x - 2);
if (nm > spots)
nm = spots;
level++;
while (nm--)
{
spots = 0;
if (find_floor(rp, &mp, MAXTRIES, TRUE))
{
tp = new_item();
new_monster(rs,tp, randmonster(FALSE), &mp);
tp->t_flags |= ISMEAN; /* no sloughers in THIS room */
give_pack(rs,tp);
}
}
level--;
}

501
src/cc/rogue/options.c Normal file
View File

@@ -0,0 +1,501 @@
/*
* This file has all the code for the option command. I would rather
* this command were not necessary, but it is the only way to keep the
* wolves off of my back.
*
* @(#)options.c 4.24 (Berkeley) 05/10/83
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <stdlib.h>
//#include <curses.h>
//#include <ctype.h>
//#include <string.h>
#include "rogue.h"
#define EQSTR(a, b, c) (strncmp(a, b, c) == 0)
#define NUM_OPTS (sizeof optlist / sizeof (OPTION))
/*
* description of an option and what to do with it
*/
struct optstruct {
char *o_name; /* option name */
char *o_prompt; /* prompt for interactive entry */
void *o_opt; /* pointer to thing to set */
/* function to print value */
void (*o_putfunc)(void *opt);
/* function to get value interactively */
int (*o_getfunc)(struct rogue_state *rs,void *opt, WINDOW *win);
};
typedef struct optstruct OPTION;
void pr_optname(OPTION *op);
OPTION optlist[] = {
{"terse", "Terse output",
&terse, put_bool, get_bool },
{"flush", "Flush typeahead during battle",
&fight_flush, put_bool, get_bool },
{"jump", "Show position only at end of run",
&jump, put_bool, get_bool },
{"seefloor", "Show the lamp-illuminated floor",
&see_floor, put_bool, get_sf },
{"passgo", "Follow turnings in passageways",
&passgo, put_bool, get_bool },
{"tombstone", "Print out tombstone when killed",
&tombstone, put_bool, get_bool },
{"inven", "Inventory style",
&inv_type, put_inv_t, get_inv_t },
{"name", "Name",
whoami, put_str, get_str },
{"fruit", "Fruit",
fruit, put_str, get_str },
{"file", "Save file",
file_name, put_str, get_str }
};
/*
* option:
* Print and then set options from the terminal
*/
void
option(struct rogue_state *rs)
{
OPTION *op;
int retval;
wclear(hw);
/*
* Display current values of options
*/
for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)
{
pr_optname(op);
(*op->o_putfunc)(op->o_opt);
waddch(hw, '\n');
}
/*
* Set values
*/
wmove(hw, 0, 0);
for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)
{
pr_optname(op);
retval = (*op->o_getfunc)(rs,op->o_opt, hw);
if (retval)
{
if (retval == QUIT)
break;
else if (op > optlist) { /* MINUS */
wmove(hw, (int)(op - optlist) - 1, 0);
op -= 2;
}
else /* trying to back up beyond the top */
{
putchar('\007');
wmove(hw, 0, 0);
op--;
}
}
}
/*
* Switch back to original screen
*/
wmove(hw, LINES - 1, 0);
waddstr(hw, "--Press space to continue--");
wrefresh(hw);
wait_for(rs,' ');
clearok(curscr, TRUE);
touchwin(stdscr);
after = FALSE;
}
/*
* pr_optname:
* Print out the option name prompt
*/
void
pr_optname(OPTION *op)
{
wprintw(hw, "%s (\"%s\"): ", op->o_prompt, op->o_name);
}
/*
* put_bool
* Put out a boolean
*/
void
put_bool(void *b)
{
waddstr(hw, *(bool *) b ? "True" : "False");
}
/*
* put_str:
* Put out a string
*/
void
put_str(void *str)
{
waddstr(hw, (char *) str);
}
/*
* put_inv_t:
* Put out an inventory type
*/
void
put_inv_t(void *ip)
{
waddstr(hw, inv_t_name[*(int *) ip]);
}
/*
* get_bool:
* Allow changing a boolean option and print it out
*/
int
get_bool(struct rogue_state *rs,void *vp, WINDOW *win)
{
bool *bp = (bool *) vp;
int oy, ox;
bool op_bad;
op_bad = TRUE;
getyx(win, oy, ox);
waddstr(win, *bp ? "True" : "False");
while (op_bad)
{
wmove(win, oy, ox);
wrefresh(win);
switch (readchar(rs))
{
case 't':
case 'T':
*bp = TRUE;
op_bad = FALSE;
break;
case 'f':
case 'F':
*bp = FALSE;
op_bad = FALSE;
break;
case '\n':
case '\r':
op_bad = FALSE;
break;
case ESCAPE:
return QUIT;
case '-':
return MINUS;
default:
wmove(win, oy, ox + 10);
waddstr(win, "(T or F)");
}
}
wmove(win, oy, ox);
waddstr(win, *bp ? "True" : "False");
waddch(win, '\n');
return NORM;
}
/*
* get_sf:
* Change value and handle transition problems from see_floor to
* !see_floor.
*/
int
get_sf(struct rogue_state *rs,void *vp, WINDOW *win)
{
bool *bp = (bool *) vp;
bool was_sf;
int retval;
was_sf = see_floor;
retval = get_bool(rs,bp, win);
if (retval == QUIT) return(QUIT);
if (was_sf != see_floor)
{
if (!see_floor) {
see_floor = TRUE;
erase_lamp(&hero, proom);
see_floor = FALSE;
}
else
look(rs,FALSE);
}
return(NORM);
}
/*
* get_str:
* Set a string option
*/
#define MAXINP 50 /* max string to read from terminal or environment */
int
get_str(struct rogue_state *rs,void *vopt, WINDOW *win)
{
char *opt = (char *) vopt;
char *sp;
int oy, ox;
int i;
signed char c;
static char buf[MAXSTR];
getyx(win, oy, ox);
wrefresh(win);
/*
* loop reading in the string, and put it in a temporary buffer
*/
for (sp = buf; (c = readchar(rs)) != '\n' && c != '\r' && c != ESCAPE;
wclrtoeol(win), wrefresh(win))
{
if (c == -1)
continue;
else if (c == erasechar()) /* process erase character */
{
if (sp > buf)
{
sp--;
for (i = (int) strlen(unctrl(*sp)); i; i--)
waddch(win, '\b');
}
continue;
}
else if (c == killchar()) /* process kill character */
{
sp = buf;
wmove(win, oy, ox);
continue;
}
else if (sp == buf)
{
if (c == '-' && win != stdscr)
break;
else if (c == '~')
{
strcpy(buf, home);
waddstr(win, home);
sp += strlen(home);
continue;
}
}
if (sp >= &buf[MAXINP] || !(isprint(c) || c == ' '))
putchar(CTRL('G'));
else
{
*sp++ = c;
waddstr(win, unctrl(c));
}
}
*sp = '\0';
if (sp > buf) /* only change option if something has been typed */
strucpy(opt, buf, (int) strlen(buf));
mvwprintw(win, oy, ox, "%s\n", opt);
wrefresh(win);
if (win == stdscr)
mpos += (int)(sp - buf);
if (c == '-')
return MINUS;
else if (c == ESCAPE)
return QUIT;
else
return NORM;
}
/*
* get_inv_t
* Get an inventory type name
*/
int
get_inv_t(struct rogue_state *rs,void *vp, WINDOW *win)
{
int *ip = (int *) vp;
int oy, ox;
bool op_bad;
op_bad = TRUE;
getyx(win, oy, ox);
waddstr(win, inv_t_name[*ip]);
while (op_bad)
{
wmove(win, oy, ox);
wrefresh(win);
switch (readchar(rs))
{
case 'o':
case 'O':
*ip = INV_OVER;
op_bad = FALSE;
break;
case 's':
case 'S':
*ip = INV_SLOW;
op_bad = FALSE;
break;
case 'c':
case 'C':
*ip = INV_CLEAR;
op_bad = FALSE;
break;
case '\n':
case '\r':
op_bad = FALSE;
break;
case ESCAPE:
return QUIT;
case '-':
return MINUS;
default:
wmove(win, oy, ox + 15);
waddstr(win, "(O, S, or C)");
}
}
mvwprintw(win, oy, ox, "%s\n", inv_t_name[*ip]);
return NORM;
}
#ifdef MASTER
/*
* get_num:
* Get a numeric option
*/
int
get_num(struct rogue_state *rs,void *vp, WINDOW *win)
{
short *opt = (short *) vp;
int i;
static char buf[MAXSTR];
if ((i = get_str(rs,buf, win)) == NORM)
*opt = (short) atoi(buf);
return i;
}
#endif
/*
* parse_opts:
* Parse options from string, usually taken from the environment.
* The string is a series of comma seperated values, with booleans
* being stated as "name" (true) or "noname" (false), and strings
* being "name=....", with the string being defined up to a comma
* or the end of the entire option string.
*/
void
parse_opts(char *str)
{
char *sp;
OPTION *op;
int len;
const char **i;
char *start;
while (*str)
{
/*
* Get option name
*/
for (sp = str; isalpha(*sp); sp++)
continue;
len = (int)(sp - str);
/*
* Look it up and deal with it
*/
for (op = optlist; op <= &optlist[NUM_OPTS-1]; op++)
if (EQSTR(str, op->o_name, len))
{
if (op->o_putfunc == put_bool) /* if option is a boolean */
*(bool *)op->o_opt = TRUE; /* NOSTRICT */
else /* string option */
{
/*
* Skip to start of string value
*/
for (str = sp + 1; *str == '='; str++)
continue;
if (*str == '~')
{
strcpy((char *) op->o_opt, home); /* NOSTRICT */
start = (char *) op->o_opt + strlen(home);/* NOSTRICT */
while (*++str == '/')
continue;
}
else
start = (char *) op->o_opt; /* NOSTRICT */
/*
* Skip to end of string value
*/
for (sp = str + 1; *sp && *sp != ','; sp++)
continue;
/*
* check for type of inventory
*/
if (op->o_putfunc == put_inv_t)
{
if (islower(*str))
*str = (char) toupper(*str);
for (i = inv_t_name; i <= &inv_t_name[INV_CLEAR]; i++)
if (strncmp(str, *i, sp - str) == 0)
{
inv_type = (int)(i - inv_t_name);
break;
}
}
else
strucpy(start, str, (int)(sp - str));
}
break;
}
/*
* check for "noname" for booleans
*/
else if (op->o_putfunc == put_bool
&& EQSTR(str, "no", 2) && EQSTR(str + 2, op->o_name, len - 2))
{
*(bool *)op->o_opt = FALSE; /* NOSTRICT */
break;
}
/*
* skip to start of next option name
*/
while (*sp && !isalpha(*sp))
sp++;
str = sp;
}
}
/*
* strucpy:
* Copy string using unctrl for things
*/
void
strucpy(char *s1, char *s2, int len)
{
if (len > MAXINP)
len = MAXINP;
while (len--)
{
if (isprint(*s2) || *s2 == ' ')
*s1++ = *s2;
s2++;
}
*s1 = '\0';
}

515
src/cc/rogue/pack.c Normal file
View File

@@ -0,0 +1,515 @@
/*
* Routines to deal with the pack
*
* @(#)pack.c 4.40 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <string.h>
//#include <curses.h>
//#include <ctype.h>
#include "rogue.h"
/*
* add_pack:
* Pick up an object and add it to the pack. If the argument is
* non-null use it as the linked_list pointer instead of gettting
* it off the ground.
*/
void
add_pack(struct rogue_state *rs,THING *obj, bool silent)
{
THING *op, *lp;
bool from_floor;
from_floor = FALSE;
if (obj == NULL)
{
if ((obj = find_obj(rs,hero.y, hero.x)) == NULL)
return;
from_floor = TRUE;
}
/*
* Check for and deal with scare monster scrolls
*/
if (obj->o_type == SCROLL && obj->o_which == S_SCARE)
if (obj->o_flags & ISFOUND)
{
detach(lvl_obj, obj);
mvaddch(hero.y, hero.x, floor_ch());
chat(hero.y, hero.x) = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
discard(obj);
msg(rs,"the scroll turns to dust as you pick it up");
return;
}
if (pack == NULL)
{
pack = obj;
obj->o_packch = pack_char();
inpack++;
}
else
{
lp = NULL;
for (op = pack; op != NULL; op = next(op))
{
if (op->o_type != obj->o_type)
lp = op;
else
{
while (op->o_type == obj->o_type && op->o_which != obj->o_which)
{
lp = op;
if (next(op) == NULL)
break;
else
op = next(op);
}
if (op->o_type == obj->o_type && op->o_which == obj->o_which)
{
if (ISMULT(op->o_type))
{
if (!pack_room(rs,from_floor, obj))
return;
op->o_count++;
dump_it:
discard(obj);
obj = op;
lp = NULL;
goto out;
}
else if (obj->o_group)
{
lp = op;
while (op->o_type == obj->o_type
&& op->o_which == obj->o_which
&& op->o_group != obj->o_group)
{
lp = op;
if (next(op) == NULL)
break;
else
op = next(op);
}
if (op->o_type == obj->o_type
&& op->o_which == obj->o_which
&& op->o_group == obj->o_group)
{
op->o_count += obj->o_count;
inpack--;
if (!pack_room(rs,from_floor, obj))
return;
goto dump_it;
}
}
else
lp = op;
}
out:
break;
}
}
if (lp != NULL)
{
if (!pack_room(rs,from_floor, obj))
return;
else
{
obj->o_packch = pack_char();
next(obj) = next(lp);
prev(obj) = lp;
if (next(lp) != NULL)
prev(next(lp)) = obj;
next(lp) = obj;
}
}
}
obj->o_flags |= ISFOUND;
/*
* If this was the object of something's desire, that monster will
* get mad and run at the hero.
*/
for (op = mlist; op != NULL; op = next(op))
if (op->t_dest == &obj->o_pos)
op->t_dest = &hero;
if (obj->o_type == AMULET)
amulet = TRUE;
/*
* Notify the user
*/
if (!silent)
{
if (!terse)
addmsg(rs,"you now have ");
msg(rs,"%s (%c)", inv_name(obj, !terse), obj->o_packch);
}
}
/*
* pack_room:
* See if there's room in the pack. If not, print out an
* appropriate message
*/
bool
pack_room(struct rogue_state *rs,bool from_floor, THING *obj)
{
inpack = num_packitems();
if (++inpack > MAXPACK)
{
if (!terse)
addmsg(rs,"there's ");
addmsg(rs,"no room");
if (!terse)
addmsg(rs," in your pack");
endmsg(rs);
if (from_floor)
move_msg(rs,obj);
inpack = MAXPACK;
return FALSE;
}
//fprintf(stderr,"inpack.%d vs MAX.%d\n",inpack,MAXPACK), sleep(2);
if (from_floor)
{
detach(lvl_obj, obj);
mvaddch(hero.y, hero.x, floor_ch());
chat(hero.y, hero.x) = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
}
return TRUE;
}
/*
* leave_pack:
* take an item out of the pack
*/
THING *
leave_pack(struct rogue_state *rs,THING *obj, bool newobj, bool all)
{
THING *nobj;
inpack--;
nobj = obj;
if (obj->o_count > 1 && !all)
{
last_pick = obj;
obj->o_count--;
if (obj->o_group)
inpack++;
if (newobj)
{
nobj = new_item();
*nobj = *obj;
next(nobj) = NULL;
prev(nobj) = NULL;
nobj->o_count = 1;
}
}
else
{
last_pick = NULL;
pack_used[obj->o_packch - 'a'] = FALSE;
detach(pack, obj);
}
return nobj;
}
/*
* pack_char:
* Return the next unused pack character.
*/
char
pack_char()
{
bool *bp;
for (bp = pack_used; *bp; bp++)
continue;
*bp = TRUE;
return (char)((int)(bp - pack_used) + 'a');
}
/*
* inventory:
* List what is in the pack. Return TRUE if there is something of
* the given type.
*/
int32_t num_packitems()
{
THING *list = pack;
int32_t type = 0,n = 0;
for (; list != NULL; list = next(list))
n++;
return(n);
}
bool
inventory(struct rogue_state *rs,THING *list, int type)
{
static char inv_temp[MAXSTR];
n_objs = 0;
for (; list != NULL; list = next(list))
{
if (type && type != list->o_type && !(type == CALLABLE &&
list->o_type != FOOD && list->o_type != AMULET) &&
!(type == R_OR_S && (list->o_type == RING || list->o_type == STICK)))
continue;
n_objs++;
#ifdef MASTER
if (!list->o_packch)
strcpy(inv_temp, "%s");
else
#endif
sprintf(inv_temp, "%c) %%s", list->o_packch);
msg_esc = TRUE;
if (add_line(rs,inv_temp, inv_name(list, FALSE)) == ESCAPE)
{
msg_esc = FALSE;
msg(rs,"");
return TRUE;
}
msg_esc = FALSE;
}
//if ( n_objs != inpack )
// fprintf(stderr,"n_objs.%d vs inpack.%d\n",n_objs,inpack), sleep(2);
if (n_objs == 0)
{
if (terse)
msg(rs,type == 0 ? (char *)"empty handed" : (char *)"nothing appropriate");
else
msg(rs,type == 0 ? (char *)"you are empty handed" : (char *)"you don't have anything appropriate");
return FALSE;
}
end_line(rs);
return TRUE;
}
/*
* pick_up:
* Add something to characters pack.
*/
void
pick_up(struct rogue_state *rs,char ch)
{
THING *obj;
if (on(player, ISLEVIT))
return;
obj = find_obj(rs,hero.y, hero.x);
if (move_on)
move_msg(rs,obj);
else
switch (ch)
{
case GOLD:
if (obj == NULL)
return;
money(rs,obj->o_goldval);
detach(lvl_obj, obj);
discard(obj);
proom->r_goldval = 0;
break;
default:
#ifdef MASTER
debug("Where did you pick a '%s' up???", unctrl(ch));
#endif
case ARMOR:
case POTION:
case FOOD:
case WEAPON:
case SCROLL:
case AMULET:
case RING:
case STICK:
add_pack(rs,(THING *) NULL, FALSE);
break;
}
}
/*
* move_msg:
* Print out the message if you are just moving onto an object
*/
void
move_msg(struct rogue_state *rs,THING *obj)
{
if (!terse)
addmsg(rs,"you ");
msg(rs,"moved onto %s", inv_name(obj, TRUE));
}
/*
* picky_inven:
* Allow player to inventory a single item
*/
void
picky_inven(struct rogue_state *rs)
{
THING *obj;
char mch;
if (pack == NULL)
msg(rs,"you aren't carrying anything");
else if (next(pack) == NULL)
msg(rs,"a) %s", inv_name(pack, FALSE));
else
{
msg(rs,terse ? (char *)"item: " : (char *)"which item do you wish to inventory: ");
mpos = 0;
if ((mch = readchar(rs)) == ESCAPE)
{
msg(rs,"");
return;
}
for (obj = pack; obj != NULL; obj = next(obj))
if (mch == obj->o_packch)
{
msg(rs,"%c) %s", mch, inv_name(obj, FALSE));
return;
}
msg(rs,"'%s' not in pack", unctrl(mch));
}
}
/*
* get_item:
* Pick something out of a pack for a purpose
*/
THING *
get_item(struct rogue_state *rs,char *purpose, int type)
{
THING *obj;
char ch;
if (pack == NULL)
msg(rs,"you aren't carrying anything");
else if (again)
if (last_pick)
return last_pick;
else
msg(rs,"you ran out");
else
{
for (;;)
{
if (!terse)
addmsg(rs,"which object do you want to ");
addmsg(rs,purpose);
if (terse)
addmsg(rs," what");
msg(rs,"? (* for list): ");
ch = readchar(rs);
mpos = 0;
/*
* Give the poor player a chance to abort the command
*/
if (ch == ESCAPE)
{
reset_last();
after = FALSE;
msg(rs,"");
return NULL;
}
n_objs = 1; /* normal case: person types one char */
if (ch == '*')
{
mpos = 0;
if (inventory(rs,pack, type) == 0)
{
after = FALSE;
return NULL;
}
continue;
}
for (obj = pack; obj != NULL; obj = next(obj))
if (obj->o_packch == ch)
break;
if (obj == NULL)
{
msg(rs,"'%s' is not a valid item",unctrl(ch));
continue;
}
else
return obj;
}
}
return NULL;
}
/*
* money:
* Add or subtract gold from the pack
*/
void
money(struct rogue_state *rs,int value)
{
purse += value;
mvaddch(hero.y, hero.x, floor_ch());
chat(hero.y, hero.x) = (proom->r_flags & ISGONE) ? PASSAGE : FLOOR;
if (value > 0)
{
if (!terse)
addmsg(rs,"you found ");
msg(rs,"%d gold pieces", value);
}
}
/*
* floor_ch:
* Return the appropriate floor character for her room
*/
char
floor_ch()
{
if (proom->r_flags & ISGONE)
return PASSAGE;
return (show_floor() ? FLOOR : ' ');
}
/*
* floor_at:
* Return the character at hero's position, taking see_floor
* into account
*/
char
floor_at()
{
char ch;
ch = chat(hero.y, hero.x);
if (ch == FLOOR)
ch = floor_ch();
return ch;
}
/*
* reset_last:
* Reset the last command when the current one is aborted
*/
void
reset_last()
{
last_comm = l_last_comm;
last_dir = l_last_dir;
last_pick = l_last_pick;
}

424
src/cc/rogue/passages.c Normal file
View File

@@ -0,0 +1,424 @@
/*
* Draw the connecting passages
*
* @(#)passages.c 4.22 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <stdlib.h>
//#include <curses.h>
#include "rogue.h"
/*
* do_passages:
* Draw all the passages on a level.
*/
void
do_passages(struct rogue_state *rs)
{
struct rdes *r1, *r2 = NULL;
int i, j;
int roomcount;
static struct rdes
{
bool conn[MAXROOMS]; /* possible to connect to room i? */
bool isconn[MAXROOMS]; /* connection been made to room i? */
bool ingraph; /* this room in graph already? */
} rdes[MAXROOMS] = {
{ { 0, 1, 0, 1, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 1, 0, 1, 0, 1, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 1, 0, 0, 0, 1, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 1, 0, 0, 0, 1, 0, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 1, 0, 1, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 0, 1, 0, 0, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 0, 0, 1, 0, 1, 0, 1 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
{ { 0, 0, 0, 0, 0, 1, 0, 1, 0 }, { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0 },
};
/*
* reinitialize room graph description
*/
for (r1 = rdes; r1 <= &rdes[MAXROOMS-1]; r1++)
{
for (j = 0; j < MAXROOMS; j++)
r1->isconn[j] = FALSE;
r1->ingraph = FALSE;
}
/*
* starting with one room, connect it to a random adjacent room and
* then pick a new room to start with.
*/
roomcount = 1;
r1 = &rdes[rnd(MAXROOMS)];
r1->ingraph = TRUE;
do
{
/*
* find a room to connect with
*/
j = 0;
for (i = 0; i < MAXROOMS; i++)
if (r1->conn[i] && !rdes[i].ingraph && rnd(++j) == 0)
r2 = &rdes[i];
/*
* if no adjacent rooms are outside the graph, pick a new room
* to look from
*/
if (j == 0)
{
do
r1 = &rdes[rnd(MAXROOMS)];
until (r1->ingraph);
}
/*
* otherwise, connect new room to the graph, and draw a tunnel
* to it
*/
else
{
r2->ingraph = TRUE;
i = (int)(r1 - rdes);
j = (int)(r2 - rdes);
conn(rs,i, j);
r1->isconn[j] = TRUE;
r2->isconn[i] = TRUE;
roomcount++;
}
} while (roomcount < MAXROOMS);
/*
* attempt to add passages to the graph a random number of times so
* that there isn't always just one unique passage through it.
*/
for (roomcount = rnd(5); roomcount > 0; roomcount--)
{
r1 = &rdes[rnd(MAXROOMS)]; /* a random room to look from */
/*
* find an adjacent room not already connected
*/
j = 0;
for (i = 0; i < MAXROOMS; i++)
if (r1->conn[i] && !r1->isconn[i] && rnd(++j) == 0)
r2 = &rdes[i];
/*
* if there is one, connect it and look for the next added
* passage
*/
if (j != 0)
{
i = (int)(r1 - rdes);
j = (int)(r2 - rdes);
conn(rs,i, j);
r1->isconn[j] = TRUE;
r2->isconn[i] = TRUE;
}
}
passnum();
}
/*
* conn:
* Draw a corridor from a room in a certain direction.
*/
void
conn(struct rogue_state *rs,int r1, int r2)
{
struct room *rpf, *rpt = NULL;
int rmt;
int distance = 0, turn_spot, turn_distance = 0;
int rm;
char direc;
static coord del, curr, turn_delta, spos, epos;
if (r1 < r2)
{
rm = r1;
if (r1 + 1 == r2)
direc = 'r';
else
direc = 'd';
}
else
{
rm = r2;
if (r2 + 1 == r1)
direc = 'r';
else
direc = 'd';
}
rpf = &rooms[rm];
/*
* Set up the movement variables, in two cases:
* first drawing one down.
*/
if (direc == 'd')
{
rmt = rm + 3; /* room # of dest */
rpt = &rooms[rmt]; /* room pointer of dest */
del.x = 0; /* direction of move */
del.y = 1;
spos.x = rpf->r_pos.x; /* start of move */
spos.y = rpf->r_pos.y;
epos.x = rpt->r_pos.x; /* end of move */
epos.y = rpt->r_pos.y;
if (!(rpf->r_flags & ISGONE)) /* if not gone pick door pos */
do
{
spos.x = rpf->r_pos.x + rnd(rpf->r_max.x - 2) + 1;
spos.y = rpf->r_pos.y + rpf->r_max.y - 1;
} while ((rpf->r_flags&ISMAZE) && !(flat(spos.y, spos.x)&F_PASS));
if (!(rpt->r_flags & ISGONE))
do
{
epos.x = rpt->r_pos.x + rnd(rpt->r_max.x - 2) + 1;
} while ((rpt->r_flags&ISMAZE) && !(flat(epos.y, epos.x)&F_PASS));
distance = abs(spos.y - epos.y) - 1; /* distance to move */
turn_delta.y = 0; /* direction to turn */
turn_delta.x = (spos.x < epos.x ? 1 : -1);
turn_distance = abs(spos.x - epos.x); /* how far to turn */
}
else if (direc == 'r') /* setup for moving right */
{
rmt = rm + 1;
rpt = &rooms[rmt];
del.x = 1;
del.y = 0;
spos.x = rpf->r_pos.x;
spos.y = rpf->r_pos.y;
epos.x = rpt->r_pos.x;
epos.y = rpt->r_pos.y;
if (!(rpf->r_flags & ISGONE))
do
{
spos.x = rpf->r_pos.x + rpf->r_max.x - 1;
spos.y = rpf->r_pos.y + rnd(rpf->r_max.y - 2) + 1;
} while ((rpf->r_flags&ISMAZE) && !(flat(spos.y, spos.x)&F_PASS));
if (!(rpt->r_flags & ISGONE))
do
{
epos.y = rpt->r_pos.y + rnd(rpt->r_max.y - 2) + 1;
} while ((rpt->r_flags&ISMAZE) && !(flat(epos.y, epos.x)&F_PASS));
distance = abs(spos.x - epos.x) - 1;
turn_delta.y = (spos.y < epos.y ? 1 : -1);
turn_delta.x = 0;
turn_distance = abs(spos.y - epos.y);
}
#ifdef MASTER
else
debug("error in connection tables");
#endif
turn_spot = rnd(distance - 1) + 1; /* where turn starts */
/*
* Draw in the doors on either side of the passage or just put #'s
* if the rooms are gone.
*/
if (!(rpf->r_flags & ISGONE))
door(rpf, &spos);
else
putpass(&spos);
if (!(rpt->r_flags & ISGONE))
door(rpt, &epos);
else
putpass(&epos);
/*
* Get ready to move...
*/
curr.x = spos.x;
curr.y = spos.y;
while (distance > 0)
{
/*
* Move to new position
*/
curr.x += del.x;
curr.y += del.y;
/*
* Check if we are at the turn place, if so do the turn
*/
if (distance == turn_spot)
while (turn_distance--)
{
putpass(&curr);
curr.x += turn_delta.x;
curr.y += turn_delta.y;
}
/*
* Continue digging along
*/
putpass(&curr);
distance--;
}
curr.x += del.x;
curr.y += del.y;
if (!ce(curr, epos))
msg(rs,"warning, connectivity problem on this level");
}
/*
* putpass:
* add a passage character or secret passage here
*/
void
putpass(coord *cp)
{
PLACE *pp;
pp = INDEX(cp->y, cp->x);
pp->p_flags |= F_PASS;
if (rnd(10) + 1 < level && rnd(40) == 0)
pp->p_flags &= ~F_REAL;
else
pp->p_ch = PASSAGE;
}
/*
* door:
* Add a door or possibly a secret door. Also enters the door in
* the exits array of the room.
*/
void
door(struct room *rm, coord *cp)
{
PLACE *pp;
rm->r_exit[rm->r_nexits++] = *cp;
if (rm->r_flags & ISMAZE)
return;
pp = INDEX(cp->y, cp->x);
if (rnd(10) + 1 < level && rnd(5) == 0)
{
if (cp->y == rm->r_pos.y || cp->y == rm->r_pos.y + rm->r_max.y - 1)
pp->p_ch = '-';
else
pp->p_ch = '|';
pp->p_flags &= ~F_REAL;
}
else
pp->p_ch = DOOR;
}
#ifdef MASTER
/*
* add_pass:
* Add the passages to the current window (wizard command)
*/
void
add_pass()
{
PLACE *pp;
int y, x;
char ch;
for (y = 1; y < NUMLINES - 1; y++)
for (x = 0; x < NUMCOLS; x++)
{
pp = INDEX(y, x);
if ((pp->p_flags & F_PASS) || pp->p_ch == DOOR ||
(!(pp->p_flags&F_REAL) && (pp->p_ch == '|' || pp->p_ch == '-')))
{
ch = pp->p_ch;
if (pp->p_flags & F_PASS)
ch = PASSAGE;
pp->p_flags |= F_SEEN;
move(y, x);
if (pp->p_monst != NULL)
pp->p_monst->t_oldch = pp->p_ch;
else if (pp->p_flags & F_REAL)
addch(ch);
else
{
standout();
addch((pp->p_flags & F_PASS) ? PASSAGE : DOOR);
standend();
}
}
}
}
#endif
/*
* passnum:
* Assign a number to each passageway
*/
static int pnum;
static bool newpnum;
void
passnum()
{
struct room *rp;
int i;
pnum = 0;
newpnum = FALSE;
for (rp = passages; rp < &passages[MAXPASS]; rp++)
rp->r_nexits = 0;
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
for (i = 0; i < rp->r_nexits; i++)
{
newpnum ^= 1;//newpnum++;
numpass(rp->r_exit[i].y, rp->r_exit[i].x);
}
}
/*
* numpass:
* Number a passageway square and its brethren
*/
void
numpass(int y, int x)
{
char *fp;
struct room *rp;
char ch;
if (x >= NUMCOLS || x < 0 || y >= NUMLINES || y <= 0)
return;
fp = &flat(y, x);
if (*fp & F_PNUM)
return;
if (newpnum)
{
pnum++;
newpnum = FALSE;
}
/*
* check to see if it is a door or secret door, i.e., a new exit,
* or a numerable type of place
*/
if ((ch = chat(y, x)) == DOOR ||
(!(*fp & F_REAL) && (ch == '|' || ch == '-')))
{
rp = &passages[pnum];
rp->r_exit[rp->r_nexits].y = y;
rp->r_exit[rp->r_nexits++].x = x;
}
else if (!(*fp & F_PASS))
return;
*fp |= pnum;
/*
* recurse on the surrounding places
*/
numpass(y + 1, x);
numpass(y - 1, x);
numpass(y, x + 1);
numpass(y, x - 1);
}

375
src/cc/rogue/potions.c Normal file
View File

@@ -0,0 +1,375 @@
/*
* Function(s) for dealing with potions
*
* @(#)potions.c 4.46 (Berkeley) 06/07/83
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <curses.h>
//#include <ctype.h>
#include "rogue.h"
typedef struct
{
int pa_flags;
void (*pa_daemon)(struct rogue_state *rs,int);
int pa_time;
char *pa_high, *pa_straight;
} PACT;
static PACT p_actions[] =
{
{ ISHUH, unconfuse, HUHDURATION, /* P_CONFUSE */
"what a tripy feeling!",
"wait, what's going on here. Huh? What? Who?" },
{ ISHALU, come_down, SEEDURATION, /* P_LSD */
"Oh, wow! Everything seems so cosmic!",
"Oh, wow! Everything seems so cosmic!" },
{ 0, NULL, 0 }, /* P_POISON */
{ 0, NULL, 0 }, /* P_STRENGTH */
{ CANSEE, unsee, SEEDURATION, /* P_SEEINVIS */
prbuf,
prbuf },
{ 0, NULL, 0 }, /* P_HEALING */
{ 0, NULL, 0 }, /* P_MFIND */
{ 0, NULL, 0 }, /* P_TFIND */
{ 0, NULL, 0 }, /* P_RAISE */
{ 0, NULL, 0 }, /* P_XHEAL */
{ 0, NULL, 0 }, /* P_HASTE */
{ 0, NULL, 0 }, /* P_RESTORE */
{ ISBLIND, sight, SEEDURATION, /* P_BLIND */
"oh, bummer! Everything is dark! Help!",
"a cloak of darkness falls around you" },
{ ISLEVIT, land, HEALTIME, /* P_LEVIT */
"oh, wow! You're floating in the air!",
"you start to float in the air" }
};
/*
* quaff:
* Quaff a potion from the pack
*/
void
quaff(struct rogue_state *rs)
{
THING *obj, *tp, *mp;
bool discardit = FALSE;
bool show, trip;
obj = get_item(rs,"quaff", POTION);
/*
* Make certain that it is somethings that we want to drink
*/
if (obj == NULL)
return;
if (obj->o_type != POTION)
{
if (!terse)
msg(rs,"yuk! Why would you want to drink that?");
else
msg(rs,"that's undrinkable");
return;
}
if (obj == cur_weapon)
cur_weapon = NULL;
/*
* Calculate the effect it has on the poor guy.
*/
trip = on(player, ISHALU);
discardit = (bool)(obj->o_count == 1);
leave_pack(rs,obj, FALSE, FALSE);
switch (obj->o_which)
{
case P_CONFUSE:
do_pot(rs,P_CONFUSE, !trip);
when P_POISON:
pot_info[P_POISON].oi_know = TRUE;
if (ISWEARING(R_SUSTSTR))
msg(rs,"you feel momentarily sick");
else
{
chg_str(-(rnd(3) + 1));
msg(rs,"you feel very sick now");
come_down(rs,0);
}
when P_HEALING:
pot_info[P_HEALING].oi_know = TRUE;
if ((pstats.s_hpt += roll(pstats.s_lvl, 4)) > max_hp)
pstats.s_hpt = ++max_hp;
sight(rs,0);
msg(rs,"you begin to feel better");
when P_STRENGTH:
pot_info[P_STRENGTH].oi_know = TRUE;
chg_str(1);
msg(rs,"you feel stronger, now. What bulging muscles!");
when P_MFIND:
player.t_flags |= SEEMONST;
fuse((void(*)(struct rogue_state *rs,int))turn_see, TRUE, HUHDURATION, AFTER);
if (!turn_see(FALSE))
msg(rs,"you have a %s feeling for a moment, then it passes",
choose_str("normal", "strange"));
when P_TFIND:
/*
* Potion of magic detection. Show the potions and scrolls
*/
show = FALSE;
if (lvl_obj != NULL)
{
wclear(hw);
for (tp = lvl_obj; tp != NULL; tp = next(tp))
{
if (is_magic(tp))
{
show = TRUE;
wmove(hw, tp->o_pos.y, tp->o_pos.x);
waddch(hw, MAGIC);
pot_info[P_TFIND].oi_know = TRUE;
}
}
for (mp = mlist; mp != NULL; mp = next(mp))
{
for (tp = mp->t_pack; tp != NULL; tp = next(tp))
{
if (is_magic(tp))
{
show = TRUE;
wmove(hw, mp->t_pos.y, mp->t_pos.x);
waddch(hw, MAGIC);
}
}
}
}
if (show)
{
pot_info[P_TFIND].oi_know = TRUE;
show_win(rs,"You sense the presence of magic on this level.--More--");
}
else
msg(rs,"you have a %s feeling for a moment, then it passes",
choose_str("normal", "strange"));
when P_LSD:
if (!trip)
{
if (on(player, SEEMONST))
turn_see(FALSE);
start_daemon(visuals, 0, BEFORE);
seenstairs = seen_stairs();
}
do_pot(rs,P_LSD, TRUE);
when P_SEEINVIS:
sprintf(prbuf, "this potion tastes like %s juice", fruit);
show = on(player, CANSEE);
do_pot(rs,P_SEEINVIS, FALSE);
if (!show)
invis_on();
sight(rs,0);
when P_RAISE:
pot_info[P_RAISE].oi_know = TRUE;
msg(rs,"you suddenly feel much more skillful");
raise_level(rs);
when P_XHEAL:
pot_info[P_XHEAL].oi_know = TRUE;
if ((pstats.s_hpt += roll(pstats.s_lvl, 8)) > max_hp)
{
if (pstats.s_hpt > max_hp + pstats.s_lvl + 1)
++max_hp;
pstats.s_hpt = ++max_hp;
}
sight(rs,0);
come_down(rs,0);
msg(rs,"you begin to feel much better");
when P_HASTE:
pot_info[P_HASTE].oi_know = TRUE;
after = FALSE;
if (add_haste(rs,TRUE))
msg(rs,"you feel yourself moving much faster");
when P_RESTORE:
if (ISRING(LEFT, R_ADDSTR))
add_str(&pstats.s_str, -cur_ring[LEFT]->o_arm);
if (ISRING(RIGHT, R_ADDSTR))
add_str(&pstats.s_str, -cur_ring[RIGHT]->o_arm);
if (pstats.s_str < max_stats.s_str)
pstats.s_str = max_stats.s_str;
if (ISRING(LEFT, R_ADDSTR))
add_str(&pstats.s_str, cur_ring[LEFT]->o_arm);
if (ISRING(RIGHT, R_ADDSTR))
add_str(&pstats.s_str, cur_ring[RIGHT]->o_arm);
msg(rs,"hey, this tastes great. It make you feel warm all over");
when P_BLIND:
do_pot(rs,P_BLIND, TRUE);
when P_LEVIT:
do_pot(rs,P_LEVIT, TRUE);
#ifdef MASTER
otherwise:
msg(rs,"what an odd tasting potion!");
return;
#endif
}
status(rs);
/*
* Throw the item away
*/
call_it(rs,&pot_info[obj->o_which]);
if (discardit)
discard(obj);
return;
}
/*
* is_magic:
* Returns true if an object radiates magic
*/
bool
is_magic(THING *obj)
{
switch (obj->o_type)
{
case ARMOR:
return (bool)((obj->o_flags&ISPROT) || obj->o_arm != a_class[obj->o_which]);
case WEAPON:
return (bool)(obj->o_hplus != 0 || obj->o_dplus != 0);
case POTION:
case SCROLL:
case STICK:
case RING:
case AMULET:
return TRUE;
}
return FALSE;
}
/*
* invis_on:
* Turn on the ability to see invisible
*/
void
invis_on()
{
THING *mp;
player.t_flags |= CANSEE;
for (mp = mlist; mp != NULL; mp = next(mp))
if (on(*mp, ISINVIS) && see_monst(mp) && !on(player, ISHALU))
mvaddch(mp->t_pos.y, mp->t_pos.x, mp->t_disguise);
}
/*
* turn_see:
* Put on or off seeing monsters on this level
*/
bool
turn_see(bool turn_off)
{
THING *mp;
bool can_see, add_new;
add_new = FALSE;
for (mp = mlist; mp != NULL; mp = next(mp))
{
move(mp->t_pos.y, mp->t_pos.x);
can_see = see_monst(mp);
if (turn_off)
{
if (!can_see)
addch(mp->t_oldch);
}
else
{
if (!can_see)
standout();
if (!on(player, ISHALU))
addch(mp->t_type);
else
addch(rnd(26) + 'A');
if (!can_see)
{
standend();
add_new ^= 1;//add_new++;
}
}
}
if (turn_off)
player.t_flags &= ~SEEMONST;
else
player.t_flags |= SEEMONST;
return add_new;
}
/*
* seen_stairs:
* Return TRUE if the player has seen the stairs
*/
bool
seen_stairs()
{
THING *tp;
move(stairs.y, stairs.x);
if (inch() == STAIRS) /* it's on the map */
return TRUE;
if (ce(hero, stairs)) /* It's under him */
return TRUE;
/*
* if a monster is on the stairs, this gets hairy
*/
if ((tp = moat(stairs.y, stairs.x)) != NULL)
{
if (see_monst(tp) && on(*tp, ISRUN)) /* if it's visible and awake */
return TRUE; /* it must have moved there */
if (on(player, SEEMONST) /* if she can detect monster */
&& tp->t_oldch == STAIRS) /* and there once were stairs */
return TRUE; /* it must have moved there */
}
return FALSE;
}
/*
* raise_level:
* The guy just magically went up a level.
*/
void
raise_level(struct rogue_state *rs)
{
pstats.s_exp = e_levels[pstats.s_lvl-1] + 1L;
check_level(rs);
}
/*
* do_pot:
* Do a potion with standard setup. This means it uses a fuse and
* turns on a flag
*/
void
do_pot(struct rogue_state *rs,int type, bool knowit)
{
PACT *pp;
int t;
pp = &p_actions[type];
if (!pot_info[type].oi_know)
pot_info[type].oi_know = knowit;
t = spread(pp->pa_time);
if (!on(player, pp->pa_flags))
{
player.t_flags |= pp->pa_flags;
fuse(pp->pa_daemon, 0, t, AFTER);
look(rs,FALSE);
}
else
lengthen(pp->pa_daemon, t);
msg(rs,choose_str(pp->pa_high, pp->pa_straight));
}

204
src/cc/rogue/rings.c Normal file
View File

@@ -0,0 +1,204 @@
/*
* Routines dealing specifically with rings
*
* @(#)rings.c 4.19 (Berkeley) 05/29/83
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <curses.h>
#include "rogue.h"
/*
* ring_on:
* Put a ring on a hand
*/
void
ring_on(struct rogue_state *rs)
{
THING *obj;
int ring;
obj = get_item(rs,"put on", RING);
/*
* Make certain that it is somethings that we want to wear
*/
if (obj == NULL)
return;
if (obj->o_type != RING)
{
if (!terse)
msg(rs,"it would be difficult to wrap that around a finger");
else
msg(rs,"not a ring");
return;
}
/*
* find out which hand to put it on
*/
if (is_current(rs,obj))
return;
if (cur_ring[LEFT] == NULL && cur_ring[RIGHT] == NULL)
{
if ((ring = gethand(rs)) < 0)
return;
}
else if (cur_ring[LEFT] == NULL)
ring = LEFT;
else if (cur_ring[RIGHT] == NULL)
ring = RIGHT;
else
{
if (!terse)
msg(rs,"you already have a ring on each hand");
else
msg(rs,"wearing two");
return;
}
cur_ring[ring] = obj;
/*
* Calculate the effect it has on the poor guy.
*/
switch (obj->o_which)
{
case R_ADDSTR:
chg_str(obj->o_arm);
break;
case R_SEEINVIS:
invis_on();
break;
case R_AGGR:
aggravate(rs);
break;
}
if (!terse)
addmsg(rs,"you are now wearing ");
msg(rs,"%s (%c)", inv_name(obj, TRUE), obj->o_packch);
}
/*
* ring_off:
* take off a ring
*/
void
ring_off(struct rogue_state *rs)
{
int ring;
THING *obj;
if (cur_ring[LEFT] == NULL && cur_ring[RIGHT] == NULL)
{
if (terse)
msg(rs,"no rings");
else
msg(rs,"you aren't wearing any rings");
return;
}
else if (cur_ring[LEFT] == NULL)
ring = RIGHT;
else if (cur_ring[RIGHT] == NULL)
ring = LEFT;
else
if ((ring = gethand(rs)) < 0)
return;
mpos = 0;
obj = cur_ring[ring];
if (obj == NULL)
{
msg(rs,"not wearing such a ring");
return;
}
if (dropcheck(rs,obj))
msg(rs,"was wearing %s(%c)", inv_name(obj, TRUE), obj->o_packch);
}
/*
* gethand:
* Which hand is the hero interested in?
*/
int
gethand(struct rogue_state *rs)
{
int c;
for (;;)
{
if (terse)
msg(rs,"left or right ring? ");
else
msg(rs,"left hand or right hand? ");
if ((c = readchar(rs)) == ESCAPE)
return -1;
mpos = 0;
if (c == 'l' || c == 'L')
return LEFT;
else if (c == 'r' || c == 'R')
return RIGHT;
if (terse)
msg(rs,"L or R");
else
msg(rs,"please type L or R");
}
}
/*
* ring_eat:
* How much food does this ring use up?
*/
int
ring_eat(int hand)
{
THING *ring;
int eat;
static int uses[] = {
1, /* R_PROTECT */ 1, /* R_ADDSTR */
1, /* R_SUSTSTR */ -3, /* R_SEARCH */
-5, /* R_SEEINVIS */ 0, /* R_NOP */
0, /* R_AGGR */ -3, /* R_ADDHIT */
-3, /* R_ADDDAM */ 2, /* R_REGEN */
-2, /* R_DIGEST */ 0, /* R_TELEPORT */
1, /* R_STEALTH */ 1 /* R_SUSTARM */
};
if ((ring = cur_ring[hand]) == NULL)
return 0;
if ((eat = uses[ring->o_which]) < 0)
eat = (rnd(-eat) == 0);
if (ring->o_which == R_DIGEST)
eat = -eat;
return eat;
}
/*
* ring_num:
* Print ring bonuses
*/
char *
ring_num(THING *obj)
{
static char buf[10];
if (!(obj->o_flags & ISKNOW))
return "";
switch (obj->o_which)
{
case R_PROTECT:
case R_ADDSTR:
case R_ADDDAM:
case R_ADDHIT:
sprintf(buf, " [%s]", num(obj->o_arm, 0, RING));
otherwise:
return "";
}
return buf;
}

460
src/cc/rogue/rip.c Normal file
View File

@@ -0,0 +1,460 @@
/*
* File for the fun ends
* Death or a total win
*
* @(#)rip.c 4.57 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <stdlib.h>
//#include <string.h>
//#include <time.h>
#include <signal.h>
//#include <sys/types.h>
//#include <ctype.h>
//#include <fcntl.h>
//#include <curses.h>
#include "rogue.h"
#include "score.h"
static char *rip[] = {
" __________\n",
" / \\\n",
" / REST \\\n",
" / IN \\\n",
" / PEACE \\\n",
" / \\\n",
" | |\n",
" | |\n",
" | killed by a |\n",
" | |\n",
" | 1980 |\n",
" *| * * * | *\n",
" ________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______\n",
0
};
/*
* score:
* Figure score and post it.
*/
/* VARARGS2 */
void
score(struct rogue_state *rs,int amount, int flags, char monst)
{
SCORE *scp;
int i;
SCORE *sc2;
SCORE *top_ten, *endp;
if ( rs->guiflag == 0 )
return;
# ifdef MASTER
int prflags = 0;
# endif
void (*fp)(int);
unsigned int uid;
static char *reason[] = {
"killed",
"quit",
"A total winner",
"killed with Amulet"
};
start_score();
if (flags >= 0
#ifdef MASTER
|| wizard
#endif
)
{
mvaddstr(LINES - 1, 0 , "[Press return to continue]");
refresh();
wgetnstr(stdscr,prbuf,80);
endwin();
printf("\n");
resetltchars();
/*
* free up space to "guarantee" there is space for the top_ten
*/
delwin(stdscr);
delwin(curscr);
if (hw != NULL)
delwin(hw);
}
top_ten = (SCORE *) malloc(numscores * sizeof (SCORE));
endp = &top_ten[numscores];
for (scp = top_ten; scp < endp; scp++)
{
scp->sc_score = 0;
for (i = 0; i < MAXSTR; i++)
scp->sc_name[i] = (unsigned char) rnd(255);
scp->sc_flags = RN;
scp->sc_level = RN;
scp->sc_monster = (unsigned short) RN;
scp->sc_uid = RN;
}
signal(SIGINT, SIG_DFL);
#ifdef MASTER
if (wizard)
if (strcmp(prbuf, "names") == 0)
prflags = 1;
else if (strcmp(prbuf, "edit") == 0)
prflags = 2;
#endif
rd_score(top_ten);
/*
* Insert her in list if need be
*/
sc2 = NULL;
if (!noscore)
{
uid = md_getuid();
for (scp = top_ten; scp < endp; scp++)
if (amount > scp->sc_score)
break;
else if (!allscore && /* only one score per nowin uid */
flags != 2 && scp->sc_uid == uid && scp->sc_flags != 2)
scp = endp;
if (scp < endp)
{
if (flags != 2 && !allscore)
{
for (sc2 = scp; sc2 < endp; sc2++)
{
if (sc2->sc_uid == uid && sc2->sc_flags != 2)
break;
}
if (sc2 >= endp)
sc2 = endp - 1;
}
else
sc2 = endp - 1;
while (sc2 > scp)
{
*sc2 = sc2[-1];
sc2--;
}
scp->sc_score = amount;
strncpy(scp->sc_name, whoami, MAXSTR);
scp->sc_flags = flags;
if (flags == 2)
scp->sc_level = max_level;
else
scp->sc_level = level;
scp->sc_monster = monst;
scp->sc_uid = uid;
sc2 = scp;
}
}
/*
* Print the list
*/
if (flags != -1)
putchar('\n');
printf("Top %s %s:\n", Numname, allscore ? "Scores" : "Rogueists");
printf(" Score Name\n");
for (scp = top_ten; scp < endp; scp++)
{
if (scp->sc_score) {
if (sc2 == scp)
md_raw_standout();
printf("%2d %5d %s: %s on level %d", (int) (scp - top_ten + 1),
scp->sc_score, scp->sc_name, reason[scp->sc_flags],
scp->sc_level);
if (scp->sc_flags == 0 || scp->sc_flags == 3)
printf(" by %s", killname((char) scp->sc_monster, TRUE));
#ifdef MASTER
if (prflags == 1)
{
printf(" (%s)", md_getrealname(scp->sc_uid));
}
else if (prflags == 2)
{
fflush(stdout);
if ( fgets(prbuf,10,stdin) != 0 )
fprintf(stderr,"fgets error\n");
if (prbuf[0] == 'd')
{
for (sc2 = scp; sc2 < endp - 1; sc2++)
*sc2 = *(sc2 + 1);
sc2 = endp - 1;
sc2->sc_score = 0;
for (i = 0; i < MAXSTR; i++)
sc2->sc_name[i] = (char) rnd(255);
sc2->sc_flags = RN;
sc2->sc_level = RN;
sc2->sc_monster = (unsigned short) RN;
scp--;
}
}
else
#endif /* MASTER */
printf(".");
if (sc2 == scp)
md_raw_standend();
putchar('\n');
}
else
break;
}
/*
* Update the list file
*/
if (sc2 != NULL)
{
if (lock_sc())
{
fp = signal(SIGINT, SIG_IGN);
wr_score(top_ten);
unlock_sc();
signal(SIGINT, fp);
}
}
free(top_ten);
}
/*
* death:
* Do something really fun when he dies
*/
void
death(struct rogue_state *rs,char monst)
{
char **dp, *killer;
struct tm *lt;
static time_t date;
//struct tm *localtime(const time_t *);
if ( rs->guiflag == 0 )
{
fprintf(stderr,"death during replay\n");
rs->replaydone = (uint32_t)time(NULL);
return;
}
signal(SIGINT, SIG_IGN);
purse -= purse / 10;
signal(SIGINT, leave);
clear();
killer = killname(monst, FALSE);
if (!tombstone)
{
mvprintw(LINES - 2, 0, "Killed by ");
killer = killname(monst, FALSE);
if (monst != 's' && monst != 'h')
printw("a%s ", vowelstr(killer));
printw("%s with %d gold", killer, purse);
}
else
{
time(&date);
lt = localtime(&date);
move(8, 0);
dp = rip;
while (*dp)
addstr(*dp++);
mvaddstr(17, center(killer), killer);
if (monst == 's' || monst == 'h')
mvaddch(16, 32, ' ');
else
mvaddstr(16, 33, vowelstr(killer));
mvaddstr(14, center(whoami), whoami);
sprintf(prbuf, "%d Au", purse);
move(15, center(prbuf));
addstr(prbuf);
sprintf(prbuf, "%4d", 1900+lt->tm_year);
mvaddstr(18, 26, prbuf);
}
move(LINES - 1, 0);
refresh();
score(rs,purse, amulet ? 3 : 0, monst);
rogue_bailout(rs);
printf("[Press return to continue]");
fflush(stdout);
if ( fgets(prbuf,10,stdin) != 0 )
;
my_exit(0);
}
/*
* center:
* Return the index to center the given string
*/
int
center(char *str)
{
return 28 - (((int)strlen(str) + 1) / 2);
}
/*
* total_winner:
* Code for a winner
*/
void
total_winner(struct rogue_state *rs)
{
THING *obj;
struct obj_info *op;
int worth = 0;
int oldpurse;
clear();
standout();
addstr(" \n");
addstr(" @ @ @ @ @ @@@ @ @ \n");
addstr(" @ @ @@ @@ @ @ @ @ \n");
addstr(" @ @ @@@ @ @ @ @ @ @@@ @@@@ @@@ @ @@@ @ \n");
addstr(" @@@@ @ @ @ @ @ @ @ @ @ @ @ @ @ @ \n");
addstr(" @ @ @ @ @ @ @ @@@@ @ @ @@@@@ @ @ @ \n");
addstr(" @ @ @ @ @ @@ @ @ @ @ @ @ @ @ @ @ \n");
addstr(" @@@ @@@ @@ @ @ @ @@@@ @@@@ @@@ @@@ @@ @ \n");
addstr(" \n");
addstr(" Congratulations, you have made it to the light of day! \n");
standend();
addstr("\nYou have joined the elite ranks of those who have escaped the\n");
addstr("Dungeons of Doom alive. You journey home and sell all your loot at\n");
addstr("a great profit and are admitted to the Fighters' Guild.\n");
mvaddstr(LINES - 1, 0, "--Press space to continue--");
refresh();
wait_for(rs,' ');
clear();
mvaddstr(0, 0, " Worth Item\n");
oldpurse = purse;
for (obj = pack; obj != NULL; obj = next(obj))
{
switch (obj->o_type)
{
case FOOD:
worth = 2 * obj->o_count;
when WEAPON:
worth = weap_info[obj->o_which].oi_worth;
worth *= 3 * (obj->o_hplus + obj->o_dplus) + obj->o_count;
obj->o_flags |= ISKNOW;
when ARMOR:
worth = arm_info[obj->o_which].oi_worth;
worth += (9 - obj->o_arm) * 100;
worth += (10 * (a_class[obj->o_which] - obj->o_arm));
obj->o_flags |= ISKNOW;
when SCROLL:
worth = scr_info[obj->o_which].oi_worth;
worth *= obj->o_count;
op = &scr_info[obj->o_which];
if (!op->oi_know)
worth /= 2;
op->oi_know = TRUE;
when POTION:
worth = pot_info[obj->o_which].oi_worth;
worth *= obj->o_count;
op = &pot_info[obj->o_which];
if (!op->oi_know)
worth /= 2;
op->oi_know = TRUE;
when RING:
op = &ring_info[obj->o_which];
worth = op->oi_worth;
if (obj->o_which == R_ADDSTR || obj->o_which == R_ADDDAM ||
obj->o_which == R_PROTECT || obj->o_which == R_ADDHIT)
{
if (obj->o_arm > 0)
worth += obj->o_arm * 100;
else
worth = 10;
}
if (!(obj->o_flags & ISKNOW))
worth /= 2;
obj->o_flags |= ISKNOW;
op->oi_know = TRUE;
when STICK:
op = &ws_info[obj->o_which];
worth = op->oi_worth;
worth += 20 * obj->o_charges;
if (!(obj->o_flags & ISKNOW))
worth /= 2;
obj->o_flags |= ISKNOW;
op->oi_know = TRUE;
when AMULET:
worth = 1000;
}
if (worth < 0)
worth = 0;
printw("%c) %5d %s\n", obj->o_packch, worth, inv_name(obj, FALSE));
purse += worth;
}
printw(" %5d Gold Pieces ", oldpurse);
refresh();
score(rs,purse, 2, ' ');
my_exit(0);
}
/*
* killname:
* Convert a code to a monster name
*/
char *
killname(char monst, bool doart)
{
struct h_list *hp;
char *sp;
bool article;
static struct h_list nlist[] = {
{'a', "arrow", TRUE},
{'b', "bolt", TRUE},
{'d', "dart", TRUE},
{'h', "hypothermia", FALSE},
{'s', "starvation", FALSE},
{'\0'}
};
if (isupper(monst))
{
sp = monsters[monst-'A'].m_name;
article = TRUE;
}
else
{
sp = "Wally the Wonder Badger";
article = FALSE;
for (hp = nlist; hp->h_ch; hp++)
if (hp->h_ch == monst)
{
sp = hp->h_desc;
article = hp->h_print;
break;
}
}
if (doart && article)
sprintf(prbuf, "a%s ", vowelstr(sp));
else
prbuf[0] = '\0';
strcat(prbuf, sp);
return prbuf;
}
/*
* death_monst:
* Return a monster appropriate for a random death.
*/
char
death_monst()
{
static char poss[] =
{
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'h', 'd', 's',
' ' /* This is provided to generate the "Wally the Wonder Badger"
message for killer */
};
return poss[rnd(sizeof poss / sizeof (char))];
}

96
src/cc/rogue/rogue.6 Normal file
View File

@@ -0,0 +1,96 @@
.\"
.\" @(#)rogue.6 6.2 (Berkeley) 5/6/86
.\"
.\" Rogue: Exploring the Dungeons of Doom
.\" Copyright (C) 1980-1983, 1985, 1986 Michael Toy, Ken Arnold and Glenn Wichman
.\" All rights reserved.
.\"
.\" See the file LICENSE.TXT for full copyright and licensing information.
.\"
.TH ROGUE 6 "May 6, 1986"
.UC 4
.SH NAME
rogue \- Exploring The Dungeons of Doom
.SH SYNOPSIS
.B rogue
[
.B \-r
]
[
.I save_file
]
[
.B \-s
]
[
.B \-d
]
.SH DESCRIPTION
.PP
.I Rogue
is a computer fantasy game with a new twist. It is crt oriented and the
object of the game is to survive the attacks of various monsters and get
a lot of gold, rather than the puzzle solving orientation of most computer
fantasy games.
.PP
To get started you really only need to know two commands. The command
.B ?
will give you a list of the available commands and the command
.B /
will identify the things you see on the screen.
.PP
To win the game (as opposed to merely playing to beat other people's high
scores) you must locate the Amulet of Yendor which is somewhere below
the 20th level of the dungeon and get it out. Nobody has achieved this
yet and if somebody does, they will probably go down in history as a hero
among heroes.
.PP
When the game ends, either by your death, when you quit, or if you (by
some miracle) manage to win,
.I rogue
will give you a list of the top-ten scorers. The scoring is based entirely
upon how much gold you get. There is a 10% penalty for getting yourself
killed.
.PP
If
.I save_file
is specified,
rogue will be restored from the specified saved game file.
If the
.B \-r
option is used, the save game file is presumed to be the default.
.PP
The
.B \-s
option will print out the list of scores.
.PP
The
.B \-d
option will kill you and try to add you to the score file.
.PP
For more detailed directions, read the document
.I "A Guide to the Dungeons of Doom."
.SH AUTHORS
Michael C. Toy,
Kenneth C. R. C. Arnold,
Glenn Wichman
.SH FILES
.DT
.ta \w'rogue.scr\ \ \ 'u
rogue.scr Score file
.br
\fB~\fP/rogue.save Default save file
.SH SEE ALSO
Michael C. Toy
and
Kenneth C. R. C. Arnold,
.I "A guide to the Dungeons of Doom"
.SH BUGS
.PP
Probably infinite
(although countably infinite).
However,
that Ice Monsters sometimes transfix you permanently is
.I not
a bug.
It's a feature.

96
src/cc/rogue/rogue.6.in Normal file
View File

@@ -0,0 +1,96 @@
.\"
.\" @(#)rogue.6 6.2 (Berkeley) 5/6/86
.\"
.\" Rogue: Exploring the Dungeons of Doom
.\" Copyright (C) 1980-1983, 1985, 1986 Michael Toy, Ken Arnold and Glenn Wichman
.\" All rights reserved.
.\"
.\" See the file LICENSE.TXT for full copyright and licensing information.
.\"
.TH ROGUE 6 "May 6, 1986"
.UC 4
.SH NAME
rogue \- Exploring The Dungeons of Doom
.SH SYNOPSIS
.B @PROGRAM@
[
.B \-r
]
[
.I save_file
]
[
.B \-s
]
[
.B \-d
]
.SH DESCRIPTION
.PP
.I Rogue
is a computer fantasy game with a new twist. It is crt oriented and the
object of the game is to survive the attacks of various monsters and get
a lot of gold, rather than the puzzle solving orientation of most computer
fantasy games.
.PP
To get started you really only need to know two commands. The command
.B ?
will give you a list of the available commands and the command
.B /
will identify the things you see on the screen.
.PP
To win the game (as opposed to merely playing to beat other people's high
scores) you must locate the Amulet of Yendor which is somewhere below
the 20th level of the dungeon and get it out. Nobody has achieved this
yet and if somebody does, they will probably go down in history as a hero
among heroes.
.PP
When the game ends, either by your death, when you quit, or if you (by
some miracle) manage to win,
.I rogue
will give you a list of the top-ten scorers. The scoring is based entirely
upon how much gold you get. There is a 10% penalty for getting yourself
killed.
.PP
If
.I save_file
is specified,
rogue will be restored from the specified saved game file.
If the
.B \-r
option is used, the save game file is presumed to be the default.
.PP
The
.B \-s
option will print out the list of scores.
.PP
The
.B \-d
option will kill you and try to add you to the score file.
.PP
For more detailed directions, read the document
.I "A Guide to the Dungeons of Doom."
.SH AUTHORS
Michael C. Toy,
Kenneth C. R. C. Arnold,
Glenn Wichman
.SH FILES
.DT
.ta \w'@SCOREFILE@\ \ \ 'u
@SCOREFILE@ Score file
.br
\fB~\fP/rogue.save Default save file
.SH SEE ALSO
Michael C. Toy
and
Kenneth C. R. C. Arnold,
.I "A guide to the Dungeons of Doom"
.SH BUGS
.PP
Probably infinite
(although countably infinite).
However,
that Ice Monsters sometimes transfix you permanently is
.I not
a bug.
It's a feature.

1
src/cc/rogue/rogue.777.0 Normal file
View File

@@ -0,0 +1 @@
llllljhhl jllllllllllllllllllkkllllklllljllljjllllllllllll

1
src/cc/rogue/rogue.777.1 Normal file
View File

@@ -0,0 +1 @@
hhhhhhhhhhkkhhhhhhhhhhhhhjjhhhhhhhhjjjjjjjjjlllllllllllllk

1
src/cc/rogue/rogue.777.2 Normal file
View File

@@ -0,0 +1 @@
lllljjllllll l ll lll l lll l ll l ljjj j j jhhhhhjjllllll

0
src/cc/rogue/rogue.777.3 Normal file
View File

748
src/cc/rogue/rogue.c Normal file
View File

@@ -0,0 +1,748 @@
/*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*
* @(#)main.c 4.22 (Berkeley) 02/05/99
*/
//#include <stdlib.h>
//#include <string.h>
#include <signal.h>
//#include <unistd.h>
//#include <curses.h>
#include "rogue.h"
#ifdef STANDALONE
#include "../komodo/src/komodo_cJSON.h"
#else
#include "../../komodo_cJSON.h"
#endif
/*
* main:
* The main program, of course
*/
struct rogue_state globalR;
void garbage_collect();
char Gametxidstr[67];
void purge_obj_guess(struct obj_info *array,int32_t n)
{
int32_t i;
for (i=0; i<n; i++)
if ( array[i].oi_guess != 0 )
free(array[i].oi_guess), array[i].oi_guess = 0;
}
void rogueiterate(struct rogue_state *rs)
{
THING *tp;
seed = rs->seed;
//clear();
purge_obj_guess(things,NUMTHINGS);
purge_obj_guess(ring_info,MAXRINGS);
purge_obj_guess(pot_info,MAXPOTIONS);
purge_obj_guess(arm_info,MAXARMORS);
purge_obj_guess(scr_info,MAXSCROLLS);
purge_obj_guess(weap_info,MAXWEAPONS + 1);
purge_obj_guess(ws_info,MAXSTICKS);
free_list(player._t._t_pack);
for (tp = mlist; tp != NULL; tp = next(tp))
free_list(tp->t_pack);
free_list(mlist);
free_list(lvl_obj);
garbage_collect();
externs_clear();
memset(d_list,0,sizeof(d_list));
memcpy(passages,origpassages,sizeof(passages));
memcpy(monsters,origmonsters,sizeof(monsters));
memcpy(things,origthings,sizeof(things));
memcpy(ring_info,origring_info,sizeof(ring_info));
memcpy(pot_info,origpot_info,sizeof(pot_info));
memcpy(arm_info,origarm_info,sizeof(arm_info));
memcpy(scr_info,origscr_info,sizeof(scr_info));
memcpy(weap_info,origweap_info,sizeof(weap_info));
memcpy(ws_info,origws_info,sizeof(ws_info));
initscr(); /* Start up cursor package */
init_probs(); /* Set up prob tables for objects */
init_player(rs); /* Set up initial player stats */
init_names(); /* Set up names of scrolls */
init_colors(); /* Set up colors of potions */
init_stones(); /* Set up stone settings of rings */
init_materials(); /* Set up materials of wands */
setup();
/*
* The screen must be at least NUMLINES x NUMCOLS
*/
if (LINES < NUMLINES || COLS < NUMCOLS)
{
printf("\nSorry, the screen must be at least %dx%d\n", NUMLINES, NUMCOLS);
endwin();
my_exit(1);
}
//fprintf(stderr,"LINES %d, COLS %d\n",LINES,COLS);
// Set up windows
if ( hw == NULL )
hw = newwin(LINES, COLS, 0, 0);
idlok(stdscr, TRUE);
idlok(hw, TRUE);
#ifdef MASTER
noscore = wizard;
#endif
new_level(rs); // Draw current level
// Start up daemons and fuses
start_daemon(runners, 0, AFTER);
start_daemon(doctor, 0, AFTER);
fuse(swander, 0, WANDERTIME, AFTER);
start_daemon(stomach, 0, AFTER);
if ( rs->restoring != 0 )
{
restore_player(rs);
}
playit(rs);
}
int32_t roguefname(char *fname,uint64_t seed,int32_t counter)
{
sprintf(fname,"rogue.%llu.%d",(long long)seed,counter);
return(0);
}
#ifdef test
int32_t flushkeystrokes(struct rogue_state *rs)
{
char fname[1024]; FILE *fp; int32_t i,retflag = -1;
roguefname(fname,rs->seed,rs->counter);
if ( (fp= fopen(fname,"wb")) != 0 )
{
if ( fwrite(rs->buffered,1,rs->num,fp) == rs->num )
{
rs->counter++;
rs->num = 0;
retflag = 0;
fclose(fp);
if ( (fp= fopen("savefile","wb")) != 0 )
{
save_file(rs,fp,0);
if ( 0 && (fp= fopen("savefile","rb")) != 0 )
{
for (i=0; i<0x150; i++)
fprintf(stderr,"%02x",fgetc(fp));
fprintf(stderr," first part rnd.%d\n",rnd(1000));
fclose(fp);
}
roguefname(fname,rs->seed,rs->counter);
if ( (fp= fopen(fname,"wb")) != 0 ) // truncate next file
fclose(fp);
//fprintf(stderr,"savefile <- %s retflag.%d\n",fname,retflag);
}
} else fprintf(stderr,"error writing (%s)\n",fname);
} else fprintf(stderr,"error creating (%s)\n",fname);
return(retflag);
}
#else
uint8_t *OS_fileptr(long *allocsizep,char *fname);
#define is_cJSON_True(json) ((json) != 0 && ((json)->type & 0xff) == cJSON_True)
int32_t rogue_setplayerdata(struct rogue_state *rs,char *gametxidstr)
{
char cmd[32768]; int32_t i,n,retval=-1; char *filestr,*pname,*statusstr,*datastr,fname[128]; long allocsize; cJSON *retjson,*array,*item;
if ( gametxidstr == 0 || *gametxidstr == 0 )
return(retval);
sprintf(fname,"%s.gameinfo",gametxidstr);
sprintf(cmd,"./komodo-cli -ac_name=ROGUE cclib gameinfo 17 \\\"[%%22%s%%22]\\\" > %s",gametxidstr,fname);
if ( system(cmd) != 0 )
fprintf(stderr,"error issuing (%s)\n",cmd);
else
{
filestr = (char *)OS_fileptr(&allocsize,fname);
if ( (retjson= cJSON_Parse(filestr)) != 0 )
{
if ( (array= jarray(&n,retjson,"players")) != 0 )
{
for (i=0; i<n; i++)
{
item = jitem(array,i);
if ( is_cJSON_True(jobj(item,"ismine")) != 0 && (statusstr= jstr(item,"status")) != 0 )
{
if ( strcmp(statusstr,"registered") == 0 )
{
retval = 0;
if ( (item= jobj(item,"player")) != 0 && (datastr= jstr(item,"data")) != 0 )
{
if ( (pname= jstr(item,"pname")) != 0 && strlen(pname) < MAXSTR-1 )
strcpy(whoami,pname);
decode_hex((uint8_t *)&rs->P,(int32_t)strlen(datastr)/2,datastr);
fprintf(stderr,"set pname[%s] %s\n",pname==0?"":pname,jprint(item,0));
rs->restoring = 1;
}
}
}
}
}
free_json(retjson);
}
free(filestr);
}
return(retval);
}
void rogue_progress(uint64_t seed,char *keystrokes,int32_t num)
{
char cmd[16384],hexstr[16384]; int32_t i;
if ( Gametxidstr[0] != 0 )
{
for (i=0; i<num; i++)
sprintf(&hexstr[i<<1],"%02x",keystrokes[i]);
hexstr[i<<1] = 0;
sprintf(cmd,"./komodo-cli -ac_name=ROGUE cclib keystrokes 17 \\\"[%%22%s%%22,%%22%s%%22]\\\" >> keystrokes.log",Gametxidstr,hexstr);
if ( system(cmd) != 0 )
fprintf(stderr,"error issuing (%s)\n",cmd);
}
}
int32_t flushkeystrokes(struct rogue_state *rs)
{
if ( rs->num > 0 )
{
rogue_progress(rs->seed,rs->buffered,rs->num);
memset(rs->buffered,0,sizeof(rs->buffered));
rs->counter++;
rs->num = 0;
}
return(0);
}
void rogue_bailout(struct rogue_state *rs)
{
char cmd[512];
flushkeystrokes(rs);
//sleep(5);
return;
fprintf(stderr,"bailing out\n");
sprintf(cmd,"./komodo-cli -ac_name=ROGUE cclib bailout 17 \\\"[%%22%s%%22]\\\" >> bailout.log",Gametxidstr);
if ( system(cmd) != 0 )
fprintf(stderr,"error issuing (%s)\n",cmd);
}
int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct rogue_player *player,int32_t sleepmillis)
{
struct rogue_state *rs; FILE *fp; int32_t i;
rs = (struct rogue_state *)calloc(1,sizeof(*rs));
rs->seed = seed;
rs->keystrokes = keystrokes;
rs->numkeys = num;
rs->sleeptime = sleepmillis * 1000;
if ( player != 0 )
{
rs->P = *player;
rs->restoring = 1;
//fprintf(stderr,"restore player packsize.%d HP.%d\n",rs->P.packsize,rs->P.hitpoints);
}
uint32_t starttime = (uint32_t)time(NULL);
rogueiterate(rs);
if ( 0 )
{
fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL) - starttime);
sleep(2);
starttime = (uint32_t)time(NULL);
for (i=0; i<10000; i++)
{
memset(rs,0,sizeof(*rs));
rs->seed = seed;
rs->keystrokes = keystrokes;
rs->numkeys = num;
rs->sleeptime = 0;
rogueiterate(rs);
}
fprintf(stderr,"elapsed %d seconds\n",(uint32_t)time(NULL)-starttime);
sleep(3);
}
if ( (fp= fopen("checkfile","wb")) != 0 )
{
save_file(rs,fp,0);
if ( newdata != 0 && rs->playersize > 0 )
memcpy(newdata,rs->playerdata,rs->playersize);
}
free(rs);
return(rs->playersize);
}
#endif
long get_filesize(FILE *fp)
{
long fsize,fpos = ftell(fp);
fseek(fp,0,SEEK_END);
fsize = ftell(fp);
fseek(fp,fpos,SEEK_SET);
return(fsize);
}
int32_t rogue_replay(uint64_t seed,int32_t sleeptime)
{
FILE *fp; char fname[1024]; char *keystrokes = 0; long num=0,fsize; int32_t i,counter = 0; struct rogue_state *rs; struct rogue_player P,*player = 0;
if ( seed == 0 )
seed = 777;
while ( 1 )
{
roguefname(fname,seed,counter);
//printf("check (%s)\n",fname);
if ( (fp= fopen(fname,"rb")) == 0 )
break;
if ( (fsize= get_filesize(fp)) <= 0 )
{
fclose(fp);
printf("fsize.%ld\n",fsize);
break;
}
if ( (keystrokes= (char *)realloc(keystrokes,num+fsize)) == 0 )
{
fprintf(stderr,"error reallocating keystrokes\n");
fclose(fp);
return(-1);
}
if ( fread(&keystrokes[num],1,fsize,fp) != fsize )
{
fprintf(stderr,"error reading keystrokes from (%s)\n",fname);
fclose(fp);
return(-1);
}
fclose(fp);
num += fsize;
counter++;
fprintf(stderr,"loaded %ld from (%s) total %ld\n",fsize,fname,num);
}
if ( num > 0 )
{
sprintf(fname,"rogue.%llu.player",(long long)seed);
if ( (fp=fopen(fname,"rb")) != 0 )
{
if ( fread(&P,1,sizeof(P),fp) > 0 )
{
//printf("max size player\n");
player = &P;
}
fclose(fp);
}
rogue_replay2(0,seed,keystrokes,num,player,150);
//mvaddstr(LINES - 2, 0, (char *)"replay completed");
endwin();
}
if ( keystrokes != 0 )
free(keystrokes);
return(num);
}
int rogue(int argc, char **argv, char **envp)
{
char *env; int lowtime; struct rogue_state *rs = &globalR;
memset(rs,0,sizeof(*rs));
if ( argc == 3 && strlen(argv[2]) == 64 )
{
rs->seed = atol(argv[1]);
strcpy(Gametxidstr,argv[2]);
if ( rogue_setplayerdata(rs,Gametxidstr) < 0 )
{
fprintf(stderr,"invalid gametxid, or already started\n");
return(-1);
}
} else rs->seed = 777;
rs->guiflag = 1;
rs->sleeptime = 1; // non-zero to allow refresh()
md_init();
#ifdef MASTER
/*
* Check to see if he is a wizard
*/
if (argc >= 2 && argv[1][0] == '\0')
if (strcmp(PASSWD, md_crypt(md_getpass("wizard's password: "), "mT")) == 0)
{
wizard = TRUE;
player.t_flags |= SEEMONST;
argv++;
argc--;
}
#endif
/*
* get home and options from environment
*/
strncpy(home, md_gethomedir(), MAXSTR);
strcpy(file_name, home);
strcat(file_name, "rogue.save");
if ((env = getenv("ROGUEOPTS")) != NULL)
parse_opts(env);
//if (env == NULL || whoami[0] == '\0')
// strucpy(whoami, md_getusername(), (int) strlen(md_getusername()));
lowtime = (int) time(NULL);
#ifdef MASTER
if (wizard && getenv("SEED") != NULL)
rs->seed = atoi(getenv("SEED"));
else
#endif
//dnum = lowtime + md_getpid();
if ( rs != 0 )
seed = rs->seed;
else seed = 777;
//dnum = (int)seed;
open_score();
/*
* Drop setuid/setgid after opening the scoreboard file.
*/
md_normaluser();
/*
* check for print-score option
*/
md_normaluser(); /* we drop any setgid/setuid priveldges here */
if (argc == 2)
{
if (strcmp(argv[1], "-s") == 0)
{
noscore = TRUE;
score(rs,0, -1, 0);
exit(0);
}
else if (strcmp(argv[1], "-d") == 0)
{
rs->seed = rnd(100); /* throw away some rnd()s to break patterns */
while (--rs->seed)
rnd(100);
purse = rnd(100) + 1;
level = rnd(100) + 1;
initscr();
getltchars();
death(rs,death_monst());
exit(0);
}
}
init_check(); /* check for legal startup */
if (argc == 2)
if (!restore(rs,argv[1], envp)) /* Note: restore will never return */
my_exit(1);
#ifdef MASTER
if (wizard)
printf("Hello %s, welcome to dungeon #%d", whoami, dnum);
else
#endif
printf("Hello %s, just a moment while I dig the dungeon... seed.%llu", whoami,(long long)rs->seed);
fflush(stdout);
rogueiterate(rs);
return(0);
}
/*
* endit:
* Exit the program abnormally.
*/
void
endit(int sig)
{
NOOP(sig);
fatal("Okay, bye bye!\n");
}
/*
* fatal:
* Exit the program, printing a message.
*/
void
fatal(char *s)
{
mvaddstr(LINES - 2, 0, s);
refresh();
endwin();
my_exit(0);
}
/*
* rnd:
* Pick a very random number.
*/
int
rnd(int range)
{
return range == 0 ? 0 : abs((int) RN) % range;
}
/*
* roll:
* Roll a number of dice
*/
int
roll(int number, int sides)
{
int dtotal = 0;
while (number--)
dtotal += rnd(sides)+1;
return dtotal;
}
/*
* tstp:
* Handle stop and start signals
*/
void
tstp(int ignored)
{
int y, x;
int oy, ox;
NOOP(ignored);
/*
* leave nicely
*/
getyx(curscr, oy, ox);
mvcur(0, COLS - 1, LINES - 1, 0);
endwin();
resetltchars();
fflush(stdout);
md_tstpsignal();
/*
* start back up again
*/
md_tstpresume();
raw();
noecho();
keypad(stdscr,1);
playltchars();
clearok(curscr, TRUE);
wrefresh(curscr);
getyx(curscr, y, x);
mvcur(y, x, oy, ox);
fflush(stdout);
//wmove(curscr,oy,ox);
#ifndef __APPLE__
curscr->_cury = oy;
curscr->_curx = ox;
#endif
}
/*
* playit:
* The main loop of the program. Loop until the game is over,
* refreshing things and looking at the proper times.
*/
void
playit(struct rogue_state *rs)
{
char *opts;
/*
* set up defaults for slow terminals
*/
if (baudrate() <= 1200)
{
terse = TRUE;
jump = TRUE;
see_floor = FALSE;
}
if (md_hasclreol())
inv_type = INV_CLEAR;
/*
* parse environment declaration of options
*/
if ((opts = getenv("ROGUEOPTS")) != NULL)
parse_opts(opts);
oldpos = hero;
oldrp = roomin(rs,&hero);
while (playing)
{
command(rs); // Command execution
if ( rs->guiflag == 0 )
{
if ( rs->replaydone != 0 )
{
if ( rs->sleeptime != 0 )
sleep(3);
return;
}
if ( rs->sleeptime != 0 )
usleep(rs->sleeptime);
}
else
{
if ( rs->needflush != 0 && rs->num > 4096 )
{
if ( flushkeystrokes(rs) == 0 )
rs->needflush = 0;
}
}
}
endit(0);
}
/*
* quit:
* Have player make certain, then exit.
*/
void
quit(int sig)
{
struct rogue_state *rs = &globalR;
int oy, ox;
//fprintf(stderr,"inside quit(%d)\n",sig);
if ( rs->guiflag != 0 )
{
NOOP(sig);
/*
* Reset the signal in case we got here via an interrupt
*/
if (!q_comm)
mpos = 0;
getyx(curscr, oy, ox);
msg(rs,"really quit?");
}
if (readchar(rs) == 'y')
{
if ( rs->guiflag != 0 )
{
signal(SIGINT, leave);
clear();
mvprintw(LINES - 2, 0, "You quit with %d gold pieces", purse);
move(LINES - 1, 0);
if ( rs->sleeptime != 0 )
refresh();
score(rs,purse, 1, 0);
flushkeystrokes(rs);
my_exit(0);
}
else
{
//score(rs,purse, 1, 0);
//fprintf(stderr,"done!\n");
}
}
else
{
move(0, 0);
clrtoeol();
status(rs);
move(oy, ox);
if ( rs->sleeptime != 0 )
refresh();
mpos = 0;
count = 0;
to_death = FALSE;
}
}
/*
* leave:
* Leave quickly, but curteously
*/
void
leave(int sig)
{
static char buf[BUFSIZ];
NOOP(sig);
setbuf(stdout, buf); /* throw away pending output */
if (!isendwin())
{
mvcur(0, COLS - 1, LINES - 1, 0);
endwin();
}
putchar('\n');
my_exit(0);
}
/*
* shell:
* Let them escape for a while
*/
void
shell(struct rogue_state *rs)
{
if ( rs != 0 && rs->guiflag != 0 )
{
/*
* Set the terminal back to original mode
*/
move(LINES-1, 0);
refresh();
endwin();
resetltchars();
putchar('\n');
in_shell = TRUE;
after = FALSE;
fflush(stdout);
/*
* Fork and do a shell
*/
md_shellescape();
printf("\n[Press return to continue]");
fflush(stdout);
noecho();
raw();
keypad(stdscr,1);
playltchars();
in_shell = FALSE;
wait_for(rs,'\n');
clearok(stdscr, TRUE);
}
else fprintf(stderr,"no shell in the blockchain\n");
}
/*
* my_exit:
* Leave the process properly
*/
void
my_exit(int st)
{
uint32_t counter;
resetltchars();
if ( globalR.guiflag != 0 )
exit(st);
else if ( counter++ < 10 )
{
fprintf(stderr,"would have exit.(%d)\n",st);
globalR.replaydone = 1;
}
}

61
src/cc/rogue/rogue.cat Normal file
View File

@@ -0,0 +1,61 @@
ROGUE(6) ROGUE(6)
NAME
rogue - Exploring The Dungeons of Doom
SYNOPSIS
rogue [ -r ] [ save_file ] [ -s ] [ -d ]
DESCRIPTION
Rogue is a computer fantasy game with a new twist. It is crt oriented
and the object of the game is to survive the attacks of various mon-
sters and get a lot of gold, rather than the puzzle solving orientation
of most computer fantasy games.
To get started you really only need to know two commands. The command
? will give you a list of the available commands and the command /
will identify the things you see on the screen.
To win the game (as opposed to merely playing to beat other people's
high scores) you must locate the Amulet of Yendor which is somewhere
below the 20th level of the dungeon and get it out. Nobody has
achieved this yet and if somebody does, they will probably go down in
history as a hero among heroes.
When the game ends, either by your death, when you quit, or if you (by
some miracle) manage to win, rogue will give you a list of the top-ten
scorers. The scoring is based entirely upon how much gold you get.
There is a 10% penalty for getting yourself killed.
If save_file is specified, rogue will be restored from the specified
saved game file. If the -r option is used, the save game file is pre-
sumed to be the default.
The -s option will print out the list of scores.
The -d option will kill you and try to add you to the score file.
For more detailed directions, read the document A Guide to the Dungeons
of Doom.
AUTHORS
Michael C. Toy, Kenneth C. R. C. Arnold, Glenn Wichman
FILES
rogue.scr Score file
~/rogue.save Default save file
SEE ALSO
Michael C. Toy and Kenneth C. R. C. Arnold, A guide to the Dungeons of
Doom
BUGS
Probably infinite (although countably infinite). However, that Ice
Monsters sometimes transfix you permanently is not a bug. It's a fea-
ture.
4th Berkeley Distribution May 6, 1986 ROGUE(6)

61
src/cc/rogue/rogue.cat.in Normal file
View File

@@ -0,0 +1,61 @@
ROGUE(6) ROGUE(6)
NAME
rogue - Exploring The Dungeons of Doom
SYNOPSIS
@PROGRAM@ [ -r ] [ save_file ] [ -s ] [ -d ]
DESCRIPTION
Rogue is a computer fantasy game with a new twist. It is crt oriented
and the object of the game is to survive the attacks of various mon-
sters and get a lot of gold, rather than the puzzle solving orientation
of most computer fantasy games.
To get started you really only need to know two commands. The command
? will give you a list of the available commands and the command /
will identify the things you see on the screen.
To win the game (as opposed to merely playing to beat other people's
high scores) you must locate the Amulet of Yendor which is somewhere
below the 20th level of the dungeon and get it out. Nobody has
achieved this yet and if somebody does, they will probably go down in
history as a hero among heroes.
When the game ends, either by your death, when you quit, or if you (by
some miracle) manage to win, rogue will give you a list of the top-ten
scorers. The scoring is based entirely upon how much gold you get.
There is a 10% penalty for getting yourself killed.
If save_file is specified, rogue will be restored from the specified
saved game file. If the -r option is used, the save game file is pre-
sumed to be the default.
The -s option will print out the list of scores.
The -d option will kill you and try to add you to the score file.
For more detailed directions, read the document A Guide to the Dungeons
of Doom.
AUTHORS
Michael C. Toy, Kenneth C. R. C. Arnold, Glenn Wichman
FILES
@SCOREFILE@ Score file
~/rogue.save Default save file
SEE ALSO
Michael C. Toy and Kenneth C. R. C. Arnold, A guide to the Dungeons of
Doom
BUGS
Probably infinite (although countably infinite). However, that Ice
Monsters sometimes transfix you permanently is not a bug. It's a fea-
ture.
4th Berkeley Distribution May 6, 1986 ROGUE(6)

View File

@@ -0,0 +1,11 @@
[Desktop Entry]
Encoding=UTF-8
Name=Rogue
GenericName=Rogue
Comment=The original curses-based adventure game
Exec=rogue
Icon=rogue.png
Terminal=true
Type=Application
Categories=Game;RolePlaying;
Version=1.0

858
src/cc/rogue/rogue.doc Normal file
View File

@@ -0,0 +1,858 @@
A Guide to the Dungeons of Doom
Michael C. Toy
Kenneth C. R. C. Arnold
Computer Systems Research Group
Department of Electrical Engineering and Computer Science
University of California
Berkeley, California 94720
ABSTRACT
Rogue is a visual CRT based fantasy game which runs
under the UNIX timesharing system. This paper de-
scribes how to play rogue, and gives a few hints for
those who might otherwise get lost in the Dungeons
of Doom.
1. Introduction
You have just finished your years as a student at the
local fighter's guild. After much practice and sweat you
have finally completed your training and are ready to embark
upon a perilous adventure. As a test of your skills, the
local guildmasters have sent you into the Dungeons of Doom.
Your task is to return with the Amulet of Yendor. Your
reward for the completion of this task will be a full mem-
bership in the local guild. In addition, you are allowed to
keep all the loot you bring back from the dungeons.
In preparation for your journey, you are given an
enchanted mace, a bow, and a quiver of arrows taken from a
dragon's hoard in the far off Dark Mountains. You are also
outfitted with elf-crafted armor and given enough food to
reach the dungeons. You say goodbye to family and friends
for what may be the last time and head up the road.
You set out on your way to the dungeons and after sev-
eral days of uneventful travel, you see the ancient ruins
that mark the entrance to the Dungeons of Doom. It is late
at night, so you make camp at the entrance and spend the
____________________
UNIX is a trademark of Bell Laboratories
USD:33-2 A Guide to the Dungeons of Doom
night sleeping under the open skies. In the morning you
gather your weapons, put on your armor, eat what is almost
your last food, and enter the dungeons.
2. What is going on here?
You have just begun a game of rogue. Your goal is to
grab as much treasure as you can, find the Amulet of Yendor,
and get out of the Dungeons of Doom alive. On the screen, a
map of where you have been and what you have seen on the
current dungeon level is kept. As you explore more of the
level, it appears on the screen in front of you.
Rogue differs from most computer fantasy games in that
it is screen oriented. Commands are all one or two
keystrokes1 and the results of your commands are displayed
graphically on the screen rather than being explained in
words.2
Another major difference between rogue and other com-
puter fantasy games is that once you have solved all the
puzzles in a standard fantasy game, it has lost most of its
excitement and it ceases to be fun. Rogue, on the other
hand, generates a new dungeon every time you play it and
even the author finds it an entertaining and exciting game.
3. What do all those things on the screen mean?
In order to understand what is going on in rogue you
have to first get some grasp of what rogue is doing with the
screen. The rogue screen is intended to replace the "You
can see ..." descriptions of standard fantasy games. Figure
1 is a sample of what a rogue screen might look like.
3.1. The bottom line
At the bottom line of the screen are a few pieces of
cryptic information describing your current status. Here is
an explanation of what these things mean:
Level This number indicates how deep you have gone in the
dungeon. It starts at one and goes up as you go
deeper into the dungeon.
Gold The number of gold pieces you have managed to find
and keep with you so far.
____________________
1 As opposed to pseudo English sentences.
2 A minimum screen size of 24 lines by 80 columns is re-
quired. If the screen is larger, only the 24x80 section
will be used for the map.
A Guide to the Dungeons of Doom USD:33-3
____________________________________________________________
------------
|..........+
|..@....]..|
|....B.....|
|..........|
-----+------
Level: 1 Gold: 0 Hp: 12(12) Str: 16(16) Arm: 4 Exp: 1/0
Figure 1
____________________________________________________________
Hp Your current and maximum health points. Health
points indicate how much damage you can take before
you die. The more you get hit in a fight, the lower
they get. You can regain health points by resting.
The number in parentheses is the maximum number your
health points can reach.
Str Your current strength and maximum ever strength.
This can be any integer less than or equal to 31, or
greater than or equal to three. The higher the num-
ber, the stronger you are. The number in the paren-
theses is the maximum strength you have attained so
far this game.
Arm Your current armor protection. This number indicates
how effective your armor is in stopping blows from
unfriendly creatures. The higher this number is, the
more effective the armor.
Exp These two numbers give your current experience level
and experience points. As you do things, you gain
experience points. At certain experience point
totals, you gain an experience level. The more expe-
rienced you are, the better you are able to fight and
to withstand magical attacks.
3.2. The top line
The top line of the screen is reserved for printing
messages that describe things that are impossible to repre-
sent visually. If you see a "--More--" on the top line,
this means that rogue wants to print another message on the
screen, but it wants to make certain that you have read the
one that is there first. To read the next message, just
USD:33-4 A Guide to the Dungeons of Doom
type a space.
3.3. The rest of the screen
The rest of the screen is the map of the level as you
have explored it so far. Each symbol on the screen repre-
sents something. Here is a list of what the various symbols
mean:
@ This symbol represents you, the adventurer.
-| These symbols represent the walls of rooms.
+ A door to/from a room.
. The floor of a room.
# The floor of a passage between rooms.
* A pile or pot of gold.
) A weapon of some sort.
] A piece of armor.
! A flask containing a magic potion.
? A piece of paper, usually a magic scroll.
= A ring with magic properties
/ A magical staff or wand
^ A trap, watch out for these.
% A staircase to other levels
: A piece of food.
A-Z The uppercase letters represent the various inhabitants
of the Dungeons of Doom. Watch out, they can be nasty
and vicious.
4. Commands
Commands are given to rogue by typing one or two char-
acters. Most commands can be preceded by a count to repeat
them (e.g. typing "10s" will do ten searches). Commands for
which counts make no sense have the count ignored. To can-
cel a count or a prefix, type <ESCAPE>. The list of com-
mands is rather long, but it can be read at any time during
the game with the "?" command. Here it is for reference,
with a short explanation of each command.
A Guide to the Dungeons of Doom USD:33-5
? The help command. Asks for a character to give help
on. If you type a "*", it will list all the commands,
otherwise it will explain what the character you typed
does.
/ This is the "What is that on the screen?" command. A
"/" followed by any character that you see on the
level, will tell you what that character is. For
instance, typing "/@" will tell you that the "@" symbol
represents you, the player.
h, H, ^H
Move left. You move one space to the left. If you use
upper case "h", you will continue to move left until
you run into something. This works for all movement
commands (e.g. "L" means run in direction "l") If you
use the "control" "h", you will continue moving in the
specified direction until you pass something interest-
ing or run into a wall. You should experiment with
this, since it is a very useful command, but very dif-
ficult to describe. This also works for all movement
commands.
j Move down.
k Move up.
l Move right.
y Move diagonally up and left.
u Move diagonally up and right.
b Move diagonally down and left.
n Move diagonally down and right.
t Throw an object. This is a prefix command. When fol-
lowed with a direction it throws an object in the spec-
ified direction. (e.g. type "th" to throw something to
the left.)
f Fight until someone dies. When followed with a direc-
tion this will force you to fight the creature in that
direction until either you or it bites the big one.
m Move onto something without picking it up. This will
move you one space in the direction you specify and, if
there is an object there you can pick up, it won't do
it.
z Zap prefix. Point a staff or wand in a given direction
and fire it. Even non-directional staves must be
USD:33-6 A Guide to the Dungeons of Doom
pointed in some direction to be used.
^ Identify trap command. If a trap is on your map and
you can't remember what type it is, you can get rogue
to remind you by getting next to it and typing "^" fol-
lowed by the direction that would move you on top of
it.
s Search for traps and secret doors. Examine each space
immediately adjacent to you for the existence of a trap
or secret door. There is a large chance that even if
there is something there, you won't find it, so you
might have to search a while before you find something.
> Climb down a staircase to the next level. Not surpris-
ingly, this can only be done if you are standing on
staircase.
< Climb up a staircase to the level above. This can't be
done without the Amulet of Yendor in your possession.
. Rest. This is the "do nothing" command. This is good
for waiting and healing.
, Pick up something. This picks up whatever you are cur-
rently standing on, if you are standing on anything at
all.
i Inventory. List what you are carrying in your pack.
I Selective inventory. Tells you what a single item in
your pack is.
q Quaff one of the potions you are carrying.
r Read one of the scrolls in your pack.
e Eat food from your pack.
w Wield a weapon. Take a weapon out of your pack and
carry it for use in combat, replacing the one you are
currently using (if any).
W Wear armor. You can only wear one suit of armor at a
time. This takes extra time.
T Take armor off. You can't remove armor that is cursed.
This takes extra time.
P Put on a ring. You can wear only two rings at a time
(one on each hand). If you aren't wearing any rings,
this command will ask you which hand you want to wear
it on, otherwise, it will place it on the unused hand.
A Guide to the Dungeons of Doom USD:33-7
The program assumes that you wield your sword in your
right hand.
R Remove a ring. If you are only wearing one ring, this
command takes it off. If you are wearing two, it will
ask you which one you wish to remove,
d Drop an object. Take something out of your pack and
leave it lying on the floor. Only one object can
occupy each space. You cannot drop a cursed object at
all if you are wielding or wearing it.
c Call an object something. If you have a type of object
in your pack which you wish to remember something
about, you can use the call command to give a name to
that type of object. This is usually used when you
figure out what a potion, scroll, ring, or staff is
after you pick it up, or when you want to remember
which of those swords in your pack you were wielding.
D Print out which things you've discovered something
about. This command will ask you what type of thing
you are interested in. If you type the character for a
given type of object (e.g. "!" for potion) it will
tell you which kinds of that type of object you've dis-
covered (i.e., figured out what they are). This com-
mand works for potions, scrolls, rings, and staves and
wands.
o Examine and set options. This command is further
explained in the section on options.
^R Redraws the screen. Useful if spurious messages or
transmission errors have messed up the display.
^P Print last message. Useful when a message disappears
before you can read it. This only repeats the last
message that was not a mistyped command so that you
don't loose anything by accidentally typing the wrong
character instead of ^P.
<ESCAPE>
Cancel a command, prefix, or count.
! Escape to a shell for some commands.
Q Quit. Leave the game.
S Save the current game in a file. It will ask you
whether you wish to use the default save file. Caveat:
Rogue won't let you start up a copy of a saved game,
and it removes the save file as soon as you start up a
restored game. This is to prevent people from saving a
USD:33-8 A Guide to the Dungeons of Doom
game just before a dangerous position and then restart-
ing it if they die. To restore a saved game, give the
file name as an argument to rogue. As in
% rogue save_file
To restart from the default save file (see below), run
% rogue -r
v Prints the program version number.
) Print the weapon you are currently wielding
] Print the armor you are currently wearing
= Print the rings you are currently wearing
@ Reprint the status line on the message line
5. Rooms
Rooms in the dungeons are either lit or dark. If you
walk into a lit room, the entire room will be drawn on the
screen as soon as you enter. If you walk into a dark room,
it will only be displayed as you explore it. Upon leaving a
room, all monsters inside the room are erased from the
screen. In the darkness you can only see one space in all
directions around you. A corridor is always dark.
6. Fighting
If you see a monster and you wish to fight it, just
attempt to run into it. Many times a monster you find will
mind its own business unless you attack it. It is often the
case that discretion is the better part of valor.
7. Objects you can find
When you find something in the dungeon, it is common to
want to pick the object up. This is accomplished in rogue
by walking over the object (unless you use the "m" prefix,
see above). If you are carrying too many things, the pro-
gram will tell you and it won't pick up the object, other-
wise it will add it to your pack and tell you what you just
picked up.
Many of the commands that operate on objects must
prompt you to find out which object you want to use. If you
change your mind and don't want to do that command after
all, just type an <ESCAPE> and the command will be aborted.
Some objects, like armor and weapons, are easily dif-
ferentiated. Others, like scrolls and potions, are given
labels which vary according to type. During a game, any two
A Guide to the Dungeons of Doom USD:33-9
of the same kind of object with the same label are the same
type. However, the labels will vary from game to game.
When you use one of these labeled objects, if its
effect is obvious, rogue will remember what it is for you.
If it's effect isn't extremely obvious you will be asked
what you want to scribble on it so you will recognize it
later, or you can use the "call" command (see above).
7.1. Weapons
Some weapons, like arrows, come in bunches, but most
come one at a time. In order to use a weapon, you must
wield it. To fire an arrow out of a bow, you must first
wield the bow, then throw the arrow. You can only wield one
weapon at a time, but you can't change weapons if the one
you are currently wielding is cursed. The commands to use
weapons are "w" (wield) and "t" (throw).
7.2. Armor
There are various sorts of armor lying around in the
dungeon. Some of it is enchanted, some is cursed, and some
is just normal. Different armor types have different armor
protection. The higher the armor protection, the more pro-
tection the armor affords against the blows of monsters.
Here is a list of the various armor types and their normal
armor protection:
+-----------------------------------------+
| Type Protection |
|None 0 |
|Leather armor 2 |
|Studded leather / Ring mail 3 |
|Scale mail 4 |
|Chain mail 5 |
|Banded mail / Splint mail 6 |
|Plate mail 7 |
+-----------------------------------------+
If a piece of armor is enchanted, its armor protection will
be higher than normal. If a suit of armor is cursed, its
armor protection will be lower, and you will not be able to
remove it. However, not all armor with a protection that is
lower than normal is cursed.
The commands to use weapons are "W" (wear) and "T"
(take off).
USD:33-10 A Guide to the Dungeons of Doom
7.3. Scrolls
Scrolls come with titles in an unknown tongue3. After
you read a scroll, it disappears from your pack. The com-
mand to use a scroll is "r" (read).
7.4. Potions
Potions are labeled by the color of the liquid inside
the flask. They disappear after being quaffed. The command
to use a scroll is "q" (quaff).
7.5. Staves and Wands
Staves and wands do the same kinds of things. Staves
are identified by a type of wood; wands by a type of metal
or bone. They are generally things you want to do to some-
thing over a long distance, so you must point them at what
you wish to affect to use them. Some staves are not
affected by the direction they are pointed, though. Staves
come with multiple magic charges, the number being random,
and when they are used up, the staff is just a piece of wood
or metal.
The command to use a wand or staff is "z" (zap)
7.6. Rings
Rings are very useful items, since they are relatively
permanent magic, unlike the usually fleeting effects of
potions, scrolls, and staves. Of course, the bad rings are
also more powerful. Most rings also cause you to use up
food more rapidly, the rate varying with the type of ring.
Rings are differentiated by their stone settings. The com-
mands to use rings are "P" (put on) and "R" (remove).
7.7. Food
Food is necessary to keep you going. If you go too
long without eating you will faint, and eventually die of
starvation. The command to use food is "e" (eat).
8. Options
Due to variations in personal tastes and conceptions of
the way rogue should do things, there are a set of options
you can set that cause rogue to behave in various different
____________________
3 Actually, it's a dialect spoken only by the twenty-sev-
en members of a tribe in Outer Mongolia, but you're not sup-
posed to know that.
A Guide to the Dungeons of Doom USD:33-11
ways.
8.1. Setting the options
There are two ways to set the options. The first is
with the "o" command of rogue; the second is with the
"ROGUEOPTS" environment variable4.
8.1.1. Using the `o' command
When you type "o" in rogue, it clears the screen and
displays the current settings for all the options. It then
places the cursor by the value of the first option and waits
for you to type. You can type a <RETURN> which means to go
to the next option, a "-" which means to go to the previous
option, an <ESCAPE> which means to return to the game, or
you can give the option a value. For boolean options this
merely involves typing "t" for true or "f" for false. For
string options, type the new value followed by a <RETURN>.
8.1.2. Using the ROGUEOPTS variable
The ROGUEOPTS variable is a string containing a comma
separated list of initial values for the various options.
Boolean variables can be turned on by listing their name or
turned off by putting a "no" in front of the name. Thus to
set up an environment variable so that jump is on, terse is
off, and the name is set to "Blue Meanie", use the command
% setenv ROGUEOPTS "jump,noterse,name=Blue Meanie"5
8.2. Option list
Here is a list of the options and an explanation of
what each one is for. The default value for each is
enclosed in square brackets. For character string options,
input over fifty characters will be ignored.
terse [noterse]
Useful for those who are tired of the sometimes lengthy
messages of rogue. This is a useful option for playing
on slow terminals, so this option defaults to terse if
you are on a slow (1200 baud or under) terminal.
____________________
4 On Version 6 systems, there is no equivalent of the
ROGUEOPTS feature.
5 For those of you who use the Bourne shell sh (1), the
commands would be
$ ROGUEOPTS="jump,noterse,name=Blue Meanie"
$ export ROGUEOPTS
USD:33-12 A Guide to the Dungeons of Doom
jump [nojump]
If this option is set, running moves will not be dis-
played until you reach the end of the move. This saves
considerable cpu and display time. This option
defaults to jump if you are using a slow terminal.
flush [noflush]
All typeahead is thrown away after each round of bat-
tle. This is useful for those who type far ahead and
then watch in dismay as a Bat kills them.
seefloor [seefloor]
Display the floor around you on the screen as you move
through dark rooms. Due to the amount of characters
generated, this option defaults to noseefloor if you
are using a slow terminal.
passgo [nopassgo]
Follow turnings in passageways. If you run in a pas-
sage and you run into stone or a wall, rogue will see
if it can turn to the right or left. If it can only
turn one way, it will turn that way. If it can turn
either or neither, it will stop. This algorithm can
sometimes lead to slightly confusing occurrences which
is why it defaults to nopassgo.
tombstone [tombstone]
Print out the tombstone at the end if you get killed.
This is nice but slow, so you can turn it off if you
like.
inven [overwrite]
Inventory type. This can have one of three values:
overwrite, slow, or clear. With overwrite the top
lines of the map are overwritten with the list when
inventory is requested or when "Which item do you wish
to . . .? " questions are answered with a "*". How-
ever, if the list is longer than a screenful, the
screen is cleared. With slow, lists are displayed one
item at a time on the top of the screen, and with
clear, the screen is cleared, the list is displayed,
and then the dungeon level is re-displayed. Due to
speed considerations, clear is the default for termi-
nals without clear-to-end-of-line capabilities.
name [account name]
This is the name of your character. It is used if you
get on the top ten scorer's list.
fruit [slime-mold]
This should hold the name of a fruit that you enjoy
eating. It is basically a whimsey that rogue uses in a
couple of places.
A Guide to the Dungeons of Doom USD:33-13
file [~/rogue.save]
The default file name for saving the game. If your
phone is hung up by accident, rogue will automatically
save the game in this file. The file name may start
with the special character "~" which expands to be your
home directory.
9. Scoring
Rogue usually maintains a list of the top scoring peo-
ple or scores on your machine. Depending on how it is set
up, it can post either the top scores or the top players.
In the latter case, each account on the machine can post
only one non-winning score on this list. If you score
higher than someone else on this list, or better your previ-
ous score on the list, you will be inserted in the proper
place under your current name. How many scores are kept can
also be set up by whoever installs it on your machine.
If you quit the game, you get out with all of your gold
intact. If, however, you get killed in the Dungeons of
Doom, your body is forwarded to your next-of-kin, along with
90% of your gold; ten percent of your gold is kept by the
Dungeons' wizard as a fee6. This should make you consider
whether you want to take one last hit at that monster and
possibly live, or quit and thus stop with whatever you have.
If you quit, you do get all your gold, but if you swing and
live, you might find more.
If you just want to see what the current top play-
ers/games list is, you can type
% rogue -s
10. Acknowledgements
Rogue was originally conceived of by Glenn Wichman and
Michael Toy. Ken Arnold and Michael Toy then smoothed out
the user interface, and added jillions of new features. We
would like to thank Bob Arnold, Michelle Busch, Andy
Hatcher, Kipp Hickman, Mark Horton, Daniel Jensen, Bill Joy,
Joe Kalash, Steve Maurer, Marty McNary, Jan Miller, and
Scott Nelson for their ideas and assistance; and also the
teeming multitudes who graciously ignored work, school, and
social life to play rogue and send us bugs, complaints, sug-
gestions, and just plain flames. And also Mom.
____________________
6 The Dungeon's wizard is named Wally the Wonder Badger.
Invocations should be accompanied by a sizable donation.

858
src/cc/rogue/rogue.doc.in Normal file
View File

@@ -0,0 +1,858 @@
A Guide to the Dungeons of Doom
Michael C. Toy
Kenneth C. R. C. Arnold
Computer Systems Research Group
Department of Electrical Engineering and Computer Science
University of California
Berkeley, California 94720
ABSTRACT
Rogue is a visual CRT based fantasy game which runs
under the UNIX timesharing system. This paper de-
scribes how to play rogue, and gives a few hints for
those who might otherwise get lost in the Dungeons
of Doom.
1. Introduction
You have just finished your years as a student at the
local fighter's guild. After much practice and sweat you
have finally completed your training and are ready to embark
upon a perilous adventure. As a test of your skills, the
local guildmasters have sent you into the Dungeons of Doom.
Your task is to return with the Amulet of Yendor. Your
reward for the completion of this task will be a full mem-
bership in the local guild. In addition, you are allowed to
keep all the loot you bring back from the dungeons.
In preparation for your journey, you are given an
enchanted mace, a bow, and a quiver of arrows taken from a
dragon's hoard in the far off Dark Mountains. You are also
outfitted with elf-crafted armor and given enough food to
reach the dungeons. You say goodbye to family and friends
for what may be the last time and head up the road.
You set out on your way to the dungeons and after sev-
eral days of uneventful travel, you see the ancient ruins
that mark the entrance to the Dungeons of Doom. It is late
at night, so you make camp at the entrance and spend the
____________________
UNIX is a trademark of Bell Laboratories
USD:33-2 A Guide to the Dungeons of Doom
night sleeping under the open skies. In the morning you
gather your weapons, put on your armor, eat what is almost
your last food, and enter the dungeons.
2. What is going on here?
You have just begun a game of rogue. Your goal is to
grab as much treasure as you can, find the Amulet of Yendor,
and get out of the Dungeons of Doom alive. On the screen, a
map of where you have been and what you have seen on the
current dungeon level is kept. As you explore more of the
level, it appears on the screen in front of you.
Rogue differs from most computer fantasy games in that
it is screen oriented. Commands are all one or two
keystrokes1 and the results of your commands are displayed
graphically on the screen rather than being explained in
words.2
Another major difference between rogue and other com-
puter fantasy games is that once you have solved all the
puzzles in a standard fantasy game, it has lost most of its
excitement and it ceases to be fun. Rogue, on the other
hand, generates a new dungeon every time you play it and
even the author finds it an entertaining and exciting game.
3. What do all those things on the screen mean?
In order to understand what is going on in rogue you
have to first get some grasp of what rogue is doing with the
screen. The rogue screen is intended to replace the "You
can see ..." descriptions of standard fantasy games. Figure
1 is a sample of what a rogue screen might look like.
3.1. The bottom line
At the bottom line of the screen are a few pieces of
cryptic information describing your current status. Here is
an explanation of what these things mean:
Level This number indicates how deep you have gone in the
dungeon. It starts at one and goes up as you go
deeper into the dungeon.
Gold The number of gold pieces you have managed to find
and keep with you so far.
____________________
1 As opposed to pseudo English sentences.
2 A minimum screen size of 24 lines by 80 columns is re-
quired. If the screen is larger, only the 24x80 section
will be used for the map.
A Guide to the Dungeons of Doom USD:33-3
____________________________________________________________
------------
|..........+
|..@....]..|
|....B.....|
|..........|
-----+------
Level: 1 Gold: 0 Hp: 12(12) Str: 16(16) Arm: 4 Exp: 1/0
Figure 1
____________________________________________________________
Hp Your current and maximum health points. Health
points indicate how much damage you can take before
you die. The more you get hit in a fight, the lower
they get. You can regain health points by resting.
The number in parentheses is the maximum number your
health points can reach.
Str Your current strength and maximum ever strength.
This can be any integer less than or equal to 31, or
greater than or equal to three. The higher the num-
ber, the stronger you are. The number in the paren-
theses is the maximum strength you have attained so
far this game.
Arm Your current armor protection. This number indicates
how effective your armor is in stopping blows from
unfriendly creatures. The higher this number is, the
more effective the armor.
Exp These two numbers give your current experience level
and experience points. As you do things, you gain
experience points. At certain experience point
totals, you gain an experience level. The more expe-
rienced you are, the better you are able to fight and
to withstand magical attacks.
3.2. The top line
The top line of the screen is reserved for printing
messages that describe things that are impossible to repre-
sent visually. If you see a "--More--" on the top line,
this means that rogue wants to print another message on the
screen, but it wants to make certain that you have read the
one that is there first. To read the next message, just
USD:33-4 A Guide to the Dungeons of Doom
type a space.
3.3. The rest of the screen
The rest of the screen is the map of the level as you
have explored it so far. Each symbol on the screen repre-
sents something. Here is a list of what the various symbols
mean:
@ This symbol represents you, the adventurer.
-| These symbols represent the walls of rooms.
+ A door to/from a room.
. The floor of a room.
# The floor of a passage between rooms.
* A pile or pot of gold.
) A weapon of some sort.
] A piece of armor.
! A flask containing a magic potion.
? A piece of paper, usually a magic scroll.
= A ring with magic properties
/ A magical staff or wand
^ A trap, watch out for these.
% A staircase to other levels
: A piece of food.
A-Z The uppercase letters represent the various inhabitants
of the Dungeons of Doom. Watch out, they can be nasty
and vicious.
4. Commands
Commands are given to rogue by typing one or two char-
acters. Most commands can be preceded by a count to repeat
them (e.g. typing "10s" will do ten searches). Commands for
which counts make no sense have the count ignored. To can-
cel a count or a prefix, type <ESCAPE>. The list of com-
mands is rather long, but it can be read at any time during
the game with the "?" command. Here it is for reference,
with a short explanation of each command.
A Guide to the Dungeons of Doom USD:33-5
? The help command. Asks for a character to give help
on. If you type a "*", it will list all the commands,
otherwise it will explain what the character you typed
does.
/ This is the "What is that on the screen?" command. A
"/" followed by any character that you see on the
level, will tell you what that character is. For
instance, typing "/@" will tell you that the "@" symbol
represents you, the player.
h, H, ^H
Move left. You move one space to the left. If you use
upper case "h", you will continue to move left until
you run into something. This works for all movement
commands (e.g. "L" means run in direction "l") If you
use the "control" "h", you will continue moving in the
specified direction until you pass something interest-
ing or run into a wall. You should experiment with
this, since it is a very useful command, but very dif-
ficult to describe. This also works for all movement
commands.
j Move down.
k Move up.
l Move right.
y Move diagonally up and left.
u Move diagonally up and right.
b Move diagonally down and left.
n Move diagonally down and right.
t Throw an object. This is a prefix command. When fol-
lowed with a direction it throws an object in the spec-
ified direction. (e.g. type "th" to throw something to
the left.)
f Fight until someone dies. When followed with a direc-
tion this will force you to fight the creature in that
direction until either you or it bites the big one.
m Move onto something without picking it up. This will
move you one space in the direction you specify and, if
there is an object there you can pick up, it won't do
it.
z Zap prefix. Point a staff or wand in a given direction
and fire it. Even non-directional staves must be
USD:33-6 A Guide to the Dungeons of Doom
pointed in some direction to be used.
^ Identify trap command. If a trap is on your map and
you can't remember what type it is, you can get rogue
to remind you by getting next to it and typing "^" fol-
lowed by the direction that would move you on top of
it.
s Search for traps and secret doors. Examine each space
immediately adjacent to you for the existence of a trap
or secret door. There is a large chance that even if
there is something there, you won't find it, so you
might have to search a while before you find something.
> Climb down a staircase to the next level. Not surpris-
ingly, this can only be done if you are standing on
staircase.
< Climb up a staircase to the level above. This can't be
done without the Amulet of Yendor in your possession.
. Rest. This is the "do nothing" command. This is good
for waiting and healing.
, Pick up something. This picks up whatever you are cur-
rently standing on, if you are standing on anything at
all.
i Inventory. List what you are carrying in your pack.
I Selective inventory. Tells you what a single item in
your pack is.
q Quaff one of the potions you are carrying.
r Read one of the scrolls in your pack.
e Eat food from your pack.
w Wield a weapon. Take a weapon out of your pack and
carry it for use in combat, replacing the one you are
currently using (if any).
W Wear armor. You can only wear one suit of armor at a
time. This takes extra time.
T Take armor off. You can't remove armor that is cursed.
This takes extra time.
P Put on a ring. You can wear only two rings at a time
(one on each hand). If you aren't wearing any rings,
this command will ask you which hand you want to wear
it on, otherwise, it will place it on the unused hand.
A Guide to the Dungeons of Doom USD:33-7
The program assumes that you wield your sword in your
right hand.
R Remove a ring. If you are only wearing one ring, this
command takes it off. If you are wearing two, it will
ask you which one you wish to remove,
d Drop an object. Take something out of your pack and
leave it lying on the floor. Only one object can
occupy each space. You cannot drop a cursed object at
all if you are wielding or wearing it.
c Call an object something. If you have a type of object
in your pack which you wish to remember something
about, you can use the call command to give a name to
that type of object. This is usually used when you
figure out what a potion, scroll, ring, or staff is
after you pick it up, or when you want to remember
which of those swords in your pack you were wielding.
D Print out which things you've discovered something
about. This command will ask you what type of thing
you are interested in. If you type the character for a
given type of object (e.g. "!" for potion) it will
tell you which kinds of that type of object you've dis-
covered (i.e., figured out what they are). This com-
mand works for potions, scrolls, rings, and staves and
wands.
o Examine and set options. This command is further
explained in the section on options.
^R Redraws the screen. Useful if spurious messages or
transmission errors have messed up the display.
^P Print last message. Useful when a message disappears
before you can read it. This only repeats the last
message that was not a mistyped command so that you
don't loose anything by accidentally typing the wrong
character instead of ^P.
<ESCAPE>
Cancel a command, prefix, or count.
! Escape to a shell for some commands.
Q Quit. Leave the game.
S Save the current game in a file. It will ask you
whether you wish to use the default save file. Caveat:
Rogue won't let you start up a copy of a saved game,
and it removes the save file as soon as you start up a
restored game. This is to prevent people from saving a
USD:33-8 A Guide to the Dungeons of Doom
game just before a dangerous position and then restart-
ing it if they die. To restore a saved game, give the
file name as an argument to rogue. As in
% rogue save_file
To restart from the default save file (see below), run
% rogue -r
v Prints the program version number.
) Print the weapon you are currently wielding
] Print the armor you are currently wearing
= Print the rings you are currently wearing
@ Reprint the status line on the message line
5. Rooms
Rooms in the dungeons are either lit or dark. If you
walk into a lit room, the entire room will be drawn on the
screen as soon as you enter. If you walk into a dark room,
it will only be displayed as you explore it. Upon leaving a
room, all monsters inside the room are erased from the
screen. In the darkness you can only see one space in all
directions around you. A corridor is always dark.
6. Fighting
If you see a monster and you wish to fight it, just
attempt to run into it. Many times a monster you find will
mind its own business unless you attack it. It is often the
case that discretion is the better part of valor.
7. Objects you can find
When you find something in the dungeon, it is common to
want to pick the object up. This is accomplished in rogue
by walking over the object (unless you use the "m" prefix,
see above). If you are carrying too many things, the pro-
gram will tell you and it won't pick up the object, other-
wise it will add it to your pack and tell you what you just
picked up.
Many of the commands that operate on objects must
prompt you to find out which object you want to use. If you
change your mind and don't want to do that command after
all, just type an <ESCAPE> and the command will be aborted.
Some objects, like armor and weapons, are easily dif-
ferentiated. Others, like scrolls and potions, are given
labels which vary according to type. During a game, any two
A Guide to the Dungeons of Doom USD:33-9
of the same kind of object with the same label are the same
type. However, the labels will vary from game to game.
When you use one of these labeled objects, if its
effect is obvious, rogue will remember what it is for you.
If it's effect isn't extremely obvious you will be asked
what you want to scribble on it so you will recognize it
later, or you can use the "call" command (see above).
7.1. Weapons
Some weapons, like arrows, come in bunches, but most
come one at a time. In order to use a weapon, you must
wield it. To fire an arrow out of a bow, you must first
wield the bow, then throw the arrow. You can only wield one
weapon at a time, but you can't change weapons if the one
you are currently wielding is cursed. The commands to use
weapons are "w" (wield) and "t" (throw).
7.2. Armor
There are various sorts of armor lying around in the
dungeon. Some of it is enchanted, some is cursed, and some
is just normal. Different armor types have different armor
protection. The higher the armor protection, the more pro-
tection the armor affords against the blows of monsters.
Here is a list of the various armor types and their normal
armor protection:
+-----------------------------------------+
| Type Protection |
|None 0 |
|Leather armor 2 |
|Studded leather / Ring mail 3 |
|Scale mail 4 |
|Chain mail 5 |
|Banded mail / Splint mail 6 |
|Plate mail 7 |
+-----------------------------------------+
If a piece of armor is enchanted, its armor protection will
be higher than normal. If a suit of armor is cursed, its
armor protection will be lower, and you will not be able to
remove it. However, not all armor with a protection that is
lower than normal is cursed.
The commands to use weapons are "W" (wear) and "T"
(take off).
USD:33-10 A Guide to the Dungeons of Doom
7.3. Scrolls
Scrolls come with titles in an unknown tongue3. After
you read a scroll, it disappears from your pack. The com-
mand to use a scroll is "r" (read).
7.4. Potions
Potions are labeled by the color of the liquid inside
the flask. They disappear after being quaffed. The command
to use a scroll is "q" (quaff).
7.5. Staves and Wands
Staves and wands do the same kinds of things. Staves
are identified by a type of wood; wands by a type of metal
or bone. They are generally things you want to do to some-
thing over a long distance, so you must point them at what
you wish to affect to use them. Some staves are not
affected by the direction they are pointed, though. Staves
come with multiple magic charges, the number being random,
and when they are used up, the staff is just a piece of wood
or metal.
The command to use a wand or staff is "z" (zap)
7.6. Rings
Rings are very useful items, since they are relatively
permanent magic, unlike the usually fleeting effects of
potions, scrolls, and staves. Of course, the bad rings are
also more powerful. Most rings also cause you to use up
food more rapidly, the rate varying with the type of ring.
Rings are differentiated by their stone settings. The com-
mands to use rings are "P" (put on) and "R" (remove).
7.7. Food
Food is necessary to keep you going. If you go too
long without eating you will faint, and eventually die of
starvation. The command to use food is "e" (eat).
8. Options
Due to variations in personal tastes and conceptions of
the way rogue should do things, there are a set of options
you can set that cause rogue to behave in various different
____________________
3 Actually, it's a dialect spoken only by the twenty-sev-
en members of a tribe in Outer Mongolia, but you're not sup-
posed to know that.
A Guide to the Dungeons of Doom USD:33-11
ways.
8.1. Setting the options
There are two ways to set the options. The first is
with the "o" command of rogue; the second is with the
"ROGUEOPTS" environment variable4.
8.1.1. Using the `o' command
When you type "o" in rogue, it clears the screen and
displays the current settings for all the options. It then
places the cursor by the value of the first option and waits
for you to type. You can type a <RETURN> which means to go
to the next option, a "-" which means to go to the previous
option, an <ESCAPE> which means to return to the game, or
you can give the option a value. For boolean options this
merely involves typing "t" for true or "f" for false. For
string options, type the new value followed by a <RETURN>.
8.1.2. Using the ROGUEOPTS variable
The ROGUEOPTS variable is a string containing a comma
separated list of initial values for the various options.
Boolean variables can be turned on by listing their name or
turned off by putting a "no" in front of the name. Thus to
set up an environment variable so that jump is on, terse is
off, and the name is set to "Blue Meanie", use the command
% setenv ROGUEOPTS "jump,noterse,name=Blue Meanie"5
8.2. Option list
Here is a list of the options and an explanation of
what each one is for. The default value for each is
enclosed in square brackets. For character string options,
input over fifty characters will be ignored.
terse [noterse]
Useful for those who are tired of the sometimes lengthy
messages of rogue. This is a useful option for playing
on slow terminals, so this option defaults to terse if
you are on a slow (1200 baud or under) terminal.
____________________
4 On Version 6 systems, there is no equivalent of the
ROGUEOPTS feature.
5 For those of you who use the Bourne shell sh (1), the
commands would be
$ ROGUEOPTS="jump,noterse,name=Blue Meanie"
$ export ROGUEOPTS
USD:33-12 A Guide to the Dungeons of Doom
jump [nojump]
If this option is set, running moves will not be dis-
played until you reach the end of the move. This saves
considerable cpu and display time. This option
defaults to jump if you are using a slow terminal.
flush [noflush]
All typeahead is thrown away after each round of bat-
tle. This is useful for those who type far ahead and
then watch in dismay as a Bat kills them.
seefloor [seefloor]
Display the floor around you on the screen as you move
through dark rooms. Due to the amount of characters
generated, this option defaults to noseefloor if you
are using a slow terminal.
passgo [nopassgo]
Follow turnings in passageways. If you run in a pas-
sage and you run into stone or a wall, rogue will see
if it can turn to the right or left. If it can only
turn one way, it will turn that way. If it can turn
either or neither, it will stop. This algorithm can
sometimes lead to slightly confusing occurrences which
is why it defaults to nopassgo.
tombstone [tombstone]
Print out the tombstone at the end if you get killed.
This is nice but slow, so you can turn it off if you
like.
inven [overwrite]
Inventory type. This can have one of three values:
overwrite, slow, or clear. With overwrite the top
lines of the map are overwritten with the list when
inventory is requested or when "Which item do you wish
to . . .? " questions are answered with a "*". How-
ever, if the list is longer than a screenful, the
screen is cleared. With slow, lists are displayed one
item at a time on the top of the screen, and with
clear, the screen is cleared, the list is displayed,
and then the dungeon level is re-displayed. Due to
speed considerations, clear is the default for termi-
nals without clear-to-end-of-line capabilities.
name [account name]
This is the name of your character. It is used if you
get on the top ten scorer's list.
fruit [slime-mold]
This should hold the name of a fruit that you enjoy
eating. It is basically a whimsey that rogue uses in a
couple of places.
A Guide to the Dungeons of Doom USD:33-13
file [~/rogue.save]
The default file name for saving the game. If your
phone is hung up by accident, rogue will automatically
save the game in this file. The file name may start
with the special character "~" which expands to be your
home directory.
9. Scoring
Rogue usually maintains a list of the top scoring peo-
ple or scores on your machine. Depending on how it is set
up, it can post either the top scores or the top players.
In the latter case, each account on the machine can post
only one non-winning score on this list. If you score
higher than someone else on this list, or better your previ-
ous score on the list, you will be inserted in the proper
place under your current name. How many scores are kept can
also be set up by whoever installs it on your machine.
If you quit the game, you get out with all of your gold
intact. If, however, you get killed in the Dungeons of
Doom, your body is forwarded to your next-of-kin, along with
90% of your gold; ten percent of your gold is kept by the
Dungeons' wizard as a fee6. This should make you consider
whether you want to take one last hit at that monster and
possibly live, or quit and thus stop with whatever you have.
If you quit, you do get all your gold, but if you swing and
live, you might find more.
If you just want to see what the current top play-
ers/games list is, you can type
% @PROGRAM@ -s
10. Acknowledgements
Rogue was originally conceived of by Glenn Wichman and
Michael Toy. Ken Arnold and Michael Toy then smoothed out
the user interface, and added jillions of new features. We
would like to thank Bob Arnold, Michelle Busch, Andy
Hatcher, Kipp Hickman, Mark Horton, Daniel Jensen, Bill Joy,
Joe Kalash, Steve Maurer, Marty McNary, Jan Miller, and
Scott Nelson for their ideas and assistance; and also the
teeming multitudes who graciously ignored work, school, and
social life to play rogue and send us bugs, complaints, sug-
gestions, and just plain flames. And also Mom.
____________________
6 The Dungeon's wizard is named Wally the Wonder Badger.
Invocations should be accompanied by a sizable donation.

865
src/cc/rogue/rogue.h Normal file
View File

@@ -0,0 +1,865 @@
/*
* Rogue definitions and variable declarations
*
* @(#)rogue.h 5.42 (Berkeley) 08/06/83
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#ifndef H_ROGUE_H
#define H_ROGUE_H
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <unistd.h>
#include <stdarg.h> /* we need va_list */
#include <stddef.h> /* we want wchar_t */
#include <stdbool.h>
#include <ctype.h>
#include <time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#ifndef DONTUSEGUI
#include <curses.h>
#else
#include "cursesd.h"
#endif
#ifdef LINES
#undef LINES
#endif
#ifdef COLS
#undef COLS
#endif
#define LINES 24
#define COLS 80
#include "extern.h"
#undef lines
#define NOOP(x) (x += 0)
#define CCHAR(x) ( (char) (x & A_CHARTEXT) )
/*
* Maximum number of different things
*/
#define MAXROOMS 9
#define MAXTHINGS 9
#define MAXOBJ 9
#define MAXPACK 23
#define MAXTRAPS 10
#define AMULETLEVEL 26
#define NUMTHINGS 7 /* number of types of things */
#define MAXPASS 13 /* upper limit on number of passages */
#define NUMLINES 24
#define NUMCOLS 80
#define STATLINE (NUMLINES - 1)
#define BORE_LEVEL 50
/*
* return values for get functions
*/
#define NORM 0 /* normal exit */
#define QUIT 1 /* quit option setting */
#define MINUS 2 /* back up one option */
/*
* inventory types
*/
#define INV_OVER 0
#define INV_SLOW 1
#define INV_CLEAR 2
/*
* All the fun defines
*/
#define when break;case
#define otherwise break;default
#define until(expr) while(!(expr))
#define next(ptr) (*ptr).l_next
#define prev(ptr) (*ptr).l_prev
#define winat(y,x) (moat(y,x) != NULL ? moat(y,x)->t_disguise : chat(y,x))
#define ce(a,b) ((a).x == (b).x && (a).y == (b).y)
#define hero player.t_pos
#define pstats player.t_stats
#define pack player.t_pack
#define proom player.t_room
#define max_hp player.t_stats.s_maxhp
#define attach(a,b) _attach(&a,b)
#define detach(a,b) _detach(&a,b)
#define free_list(a) _free_list(&a)
#undef max
#define max(a,b) ((a) > (b) ? (a) : (b))
#define on(thing,flag) ((bool)(((thing).t_flags & (flag)) != 0))
#define GOLDCALC (rnd(50 + 10 * level) + 2)
#define ISRING(h,r) (cur_ring[h] != NULL && cur_ring[h]->o_which == r)
#define ISWEARING(r) (ISRING(LEFT, r) || ISRING(RIGHT, r))
#define ISMULT(type) (type == POTION || type == SCROLL || type == FOOD)
#define INDEX(y,x) (&places[((x) << 5) + (y)])
#define chat(y,x) (places[((x) << 5) + (y)].p_ch)
#define flat(y,x) (places[((x) << 5) + (y)].p_flags)
#define moat(y,x) (places[((x) << 5) + (y)].p_monst)
#define unc(cp) (cp).y, (cp).x
#ifdef MASTER
#define debug if (wizard) msg
#endif
/*
* things that appear on the screens
*/
#define PASSAGE '#'
#define DOOR '+'
#define FLOOR '.'
#define PLAYER '@'
#define TRAP '^'
#define STAIRS '%'
#define GOLD '*'
#define POTION '!'
#define SCROLL '?'
#define MAGIC '$'
#define FOOD ':'
#define WEAPON ')'
#define ARMOR ']'
#define AMULET ','
#define RING '='
#define STICK '/'
#define CALLABLE -1
#define R_OR_S -2
/*
* Various constants
*/
#define BEARTIME spread(3)
#define SLEEPTIME spread(5)
#define HOLDTIME spread(2)
#define WANDERTIME spread(70)
#define BEFORE spread(1)
#define AFTER spread(2)
#define HEALTIME 30
#define HUHDURATION 20
#define SEEDURATION 850
#define HUNGERTIME 1300
#define MORETIME 150
#define STOMACHSIZE 2000
#define STARVETIME 850
#define ESCAPE 27
#define LEFT 0
#define RIGHT 1
#define BOLT_LENGTH 6
#define LAMPDIST 3
#ifdef MASTER
#ifndef PASSWD
#define PASSWD "mTBellIQOsLNA"
#endif
#endif
/*
* Save against things
*/
#define VS_POISON 00
#define VS_PARALYZATION 00
#define VS_DEATH 00
#define VS_BREATH 02
#define VS_MAGIC 03
/*
* Various flag bits
*/
/* flags for rooms */
#define ISDARK 0000001 /* room is dark */
#define ISGONE 0000002 /* room is gone (a corridor) */
#define ISMAZE 0000004 /* room is gone (a corridor) */
/* flags for objects */
#define ISCURSED 000001 /* object is cursed */
#define ISKNOW 0000002 /* player knows details about the object */
#define ISMISL 0000004 /* object is a missile type */
#define ISMANY 0000010 /* object comes in groups */
/* ISFOUND 0000020 ...is used for both objects and creatures */
#define ISPROT 0000040 /* armor is permanently protected */
/* flags for creatures */
#define CANHUH 0000001 /* creature can confuse */
#define CANSEE 0000002 /* creature can see invisible creatures */
#define ISBLIND 0000004 /* creature is blind */
#define ISCANC 0000010 /* creature has special qualities cancelled */
#define ISLEVIT 0000010 /* hero is levitating */
#define ISFOUND 0000020 /* creature has been seen (used for objects) */
#define ISGREED 0000040 /* creature runs to protect gold */
#define ISHASTE 0000100 /* creature has been hastened */
#define ISTARGET 000200 /* creature is the target of an 'f' command */
#define ISHELD 0000400 /* creature has been held */
#define ISHUH 0001000 /* creature is confused */
#define ISINVIS 0002000 /* creature is invisible */
#define ISMEAN 0004000 /* creature can wake when player enters room */
#define ISHALU 0004000 /* hero is on acid trip */
#define ISREGEN 0010000 /* creature can regenerate */
#define ISRUN 0020000 /* creature is running at the player */
#define SEEMONST 040000 /* hero can detect unseen monsters */
#define ISFLY 0040000 /* creature can fly */
#define ISSLOW 0100000 /* creature has been slowed */
/*
* Flags for level map
*/
#define F_PASS 0x80 /* is a passageway */
#define F_SEEN 0x40 /* have seen this spot before */
#define F_DROPPED 0x20 /* object was dropped here */
#define F_LOCKED 0x20 /* door is locked */
#define F_REAL 0x10 /* what you see is what you get */
#define F_PNUM 0x0f /* passage number mask */
#define F_TMASK 0x07 /* trap number mask */
/*
* Trap types
*/
#define T_DOOR 00
#define T_ARROW 01
#define T_SLEEP 02
#define T_BEAR 03
#define T_TELEP 04
#define T_DART 05
#define T_RUST 06
#define T_MYST 07
#define NTRAPS 8
/*
* Potion types
*/
#define P_CONFUSE 0
#define P_LSD 1
#define P_POISON 2
#define P_STRENGTH 3
#define P_SEEINVIS 4
#define P_HEALING 5
#define P_MFIND 6
#define P_TFIND 7
#define P_RAISE 8
#define P_XHEAL 9
#define P_HASTE 10
#define P_RESTORE 11
#define P_BLIND 12
#define P_LEVIT 13
#define MAXPOTIONS 14
/*
* Scroll types
*/
#define S_CONFUSE 0
#define S_MAP 1
#define S_HOLD 2
#define S_SLEEP 3
#define S_ARMOR 4
#define S_ID_POTION 5
#define S_ID_SCROLL 6
#define S_ID_WEAPON 7
#define S_ID_ARMOR 8
#define S_ID_R_OR_S 9
#define S_SCARE 10
#define S_FDET 11
#define S_TELEP 12
#define S_ENCH 13
#define S_CREATE 14
#define S_REMOVE 15
#define S_AGGR 16
#define S_PROTECT 17
#define MAXSCROLLS 18
/*
* Weapon types
*/
#define MACE 0
#define SWORD 1
#define BOW 2
#define ARROW 3
#define DAGGER 4
#define TWOSWORD 5
#define DART 6
#define SHIRAKEN 7
#define SPEAR 8
#define FLAME 9 /* fake entry for dragon breath (ick) */
#define MAXWEAPONS 9 /* this should equal FLAME */
/*
* Armor types
*/
#define LEATHER 0
#define RING_MAIL 1
#define STUDDED_LEATHER 2
#define SCALE_MAIL 3
#define CHAIN_MAIL 4
#define SPLINT_MAIL 5
#define BANDED_MAIL 6
#define PLATE_MAIL 7
#define MAXARMORS 8
/*
* Ring types
*/
#define R_PROTECT 0
#define R_ADDSTR 1
#define R_SUSTSTR 2
#define R_SEARCH 3
#define R_SEEINVIS 4
#define R_NOP 5
#define R_AGGR 6
#define R_ADDHIT 7
#define R_ADDDAM 8
#define R_REGEN 9
#define R_DIGEST 10
#define R_TELEPORT 11
#define R_STEALTH 12
#define R_SUSTARM 13
#define MAXRINGS 14
/*
* Rod/Wand/Staff types
*/
#define WS_LIGHT 0
#define WS_INVIS 1
#define WS_ELECT 2
#define WS_FIRE 3
#define WS_COLD 4
#define WS_POLYMORPH 5
#define WS_MISSILE 6
#define WS_HASTE_M 7
#define WS_SLOW_M 8
#define WS_DRAIN 9
#define WS_NOP 10
#define WS_TELAWAY 11
#define WS_TELTO 12
#define WS_CANCEL 13
#define MAXSTICKS 14
/*
* Now we define the structures and types
*/
#define SMALLVAL 0.000000000000001
#define SATOSHIDEN ((uint64_t)100000000L)
#define dstr(x) ((double)(x) / SATOSHIDEN)
#ifndef _BITS256
#define _BITS256
union _bits256 { uint8_t bytes[32]; uint16_t ushorts[16]; uint32_t uints[8]; uint64_t ulongs[4]; uint64_t txid; };
typedef union _bits256 bits256;
#endif
#ifndef ROGUE_DECLARED_PACK
struct rogue_packitem
{
int32_t type,launch,count,which,hplus,dplus,arm,flags,group;
char damage[8],hurldmg[8];
};
struct rogue_player
{
int32_t gold,hitpoints,strength,level,experience,packsize,dungeonlevel,pad;
struct rogue_packitem roguepack[MAXPACK];
};
#define ROGUE_DECLARED_PACK
#endif
struct rogue_state
{
uint64_t seed;
char *keystrokes;
uint32_t needflush,replaydone;
int32_t numkeys,ind,num,guiflag,counter,sleeptime,playersize,restoring;
struct rogue_player P;
char buffered[8192];
uint8_t playerdata[10000];
};
extern struct rogue_state globalR;
int rogue(int argc, char **argv, char **envp);
void rogueiterate(struct rogue_state *rs);
int32_t roguefname(char *fname,uint64_t seed,int32_t counter);
int32_t flushkeystrokes(struct rogue_state *rs);
int32_t rogue_restorepack(struct rogue_state *rs);
void restore_player(struct rogue_state *rs);
int32_t rogue_replay2(uint8_t *newdata,uint64_t seed,char *keystrokes,int32_t num,struct rogue_player *player,int32_t sleepmillis);
void rogue_bailout(struct rogue_state *rs);
/*
* Help list
*/
struct h_list {
char h_ch;
char *h_desc;
bool h_print;
};
/*
* Coordinate data type
*/
typedef struct {
int x;
int y;
} coord;
typedef unsigned int str_t;
/*
* Stuff about objects
*/
struct obj_info {
char *oi_name;
int oi_prob;
int oi_worth;
char *oi_guess;
bool oi_know;
};
/*
* Room structure
*/
struct room {
coord r_pos; /* Upper left corner */
coord r_max; /* Size of room */
coord r_gold; /* Where the gold is */
int r_goldval; /* How much the gold is worth */
short r_flags; /* info about the room */
int r_nexits; /* Number of exits */
coord r_exit[12]; /* Where the exits are */
};
/*
* Structure describing a fighting being
*/
struct stats {
str_t s_str; /* Strength */
int s_exp; /* Experience */
int s_lvl; /* level of mastery */
int s_arm; /* Armor class */
int s_hpt; /* Hit points */
char s_dmg[13]; /* String describing damage done */
int s_maxhp; /* Max hit points */
};
/*
* Structure for monsters and player
*/
union thing {
struct {
union thing *_l_next, *_l_prev; /* Next pointer in link */
coord _t_pos; /* Position */
bool _t_turn; /* If slowed, is it a turn to move */
char _t_type; /* What it is */
char _t_disguise; /* What mimic looks like */
char _t_oldch; /* Character that was where it was */
coord *_t_dest; /* Where it is running to */
short _t_flags; /* State word */
struct stats _t_stats; /* Physical description */
struct room *_t_room; /* Current room for thing */
union thing *_t_pack; /* What the thing is carrying */
int _t_reserved;
} _t;
struct {
union thing *_l_next, *_l_prev; /* Next pointer in link */
int _o_type; /* What kind of object it is */
coord _o_pos; /* Where it lives on the screen */
char *_o_text; /* What it says if you read it */
int _o_launch; /* What you need to launch it */
char _o_packch; /* What character it is in the pack */
char _o_damage[8]; /* Damage if used like sword */
char _o_hurldmg[8]; /* Damage if thrown */
int _o_count; /* count for plural objects */
int _o_which; /* Which object of a type it is */
int _o_hplus; /* Plusses to hit */
int _o_dplus; /* Plusses to damage */
int _o_arm; /* Armor protection */
int _o_flags; /* information about objects */
int _o_group; /* group number for this object */
char *_o_label; /* Label for object */
} _o;
};
typedef union thing THING;
#define l_next _t._l_next
#define l_prev _t._l_prev
#define t_pos _t._t_pos
#define t_turn _t._t_turn
#define t_type _t._t_type
#define t_disguise _t._t_disguise
#define t_oldch _t._t_oldch
#define t_dest _t._t_dest
#define t_flags _t._t_flags
#define t_stats _t._t_stats
#define t_pack _t._t_pack
#define t_room _t._t_room
#define t_reserved _t._t_reserved
#define o_type _o._o_type
#define o_pos _o._o_pos
#define o_text _o._o_text
#define o_launch _o._o_launch
#define o_packch _o._o_packch
#define o_damage _o._o_damage
#define o_hurldmg _o._o_hurldmg
#define o_count _o._o_count
#define o_which _o._o_which
#define o_hplus _o._o_hplus
#define o_dplus _o._o_dplus
#define o_arm _o._o_arm
#define o_charges o_arm
#define o_goldval o_arm
#define o_flags _o._o_flags
#define o_group _o._o_group
#define o_label _o._o_label
/*
* describe a place on the level map
*/
typedef struct {
char p_ch;
char p_flags;
THING *p_monst;
} PLACE;
/*
* Array containing information on all the various types of monsters
*/
struct monster {
char *m_name; /* What to call the monster */
int m_carry; /* Probability of carrying something */
short m_flags; /* things about the monster */
struct stats m_stats; /* Initial stats */
};
/*
* External variables
*/
extern const char *tr_name[],*inv_t_name[];
extern const int32_t a_class[], e_levels[];
extern const struct h_list helpstr[];
extern const char *h_names[],*m_names[];
extern const struct monster origmonsters[26];
extern const struct room origpassages[MAXPASS];
extern const struct obj_info origthings[NUMTHINGS],origring_info[MAXRINGS],origpot_info[MAXPOTIONS],origarm_info[MAXARMORS],origscr_info[MAXSCROLLS],origws_info[MAXSTICKS],origweap_info[MAXWEAPONS + 1];
extern struct monster monsters[26];
extern struct room passages[MAXPASS];
extern struct obj_info things[NUMTHINGS],ring_info[MAXRINGS],pot_info[MAXPOTIONS],arm_info[MAXARMORS],scr_info[MAXSCROLLS],weap_info[MAXWEAPONS + 1],ws_info[MAXSTICKS];
extern bool after, again, allscore, amulet, door_stop, fight_flush,
firstmove, has_hit, inv_describe, jump, kamikaze,
lower_msg, move_on, msg_esc, pack_used[],
passgo, playing, q_comm, running, save_msg, see_floor,
seenstairs, stat_msg, terse, to_death, tombstone;
extern char dir_ch, file_name[], home[], huh[],
l_last_comm, l_last_dir, last_comm, last_dir, *Numname,
outbuf[], *release, *s_names[], runch, take;
extern const char *ws_made[], *r_stones[], *p_colors[], *ws_type[];
extern int count, food_left, hungry_state, inpack,
inv_type, lastscore, level, max_hit, max_level, mpos,
n_objs, no_command, no_food, no_move, noscore, ntraps, purse,
quiet, vf_hit;
extern unsigned int numscores;
extern uint64_t seed;
extern WINDOW *hw;
extern coord delta, oldpos, stairs;
extern PLACE places[];
extern THING *cur_armor, *cur_ring[], *cur_weapon, *l_last_pick,
*last_pick, *lvl_obj, *mlist, player;
extern struct room *oldrp, rooms[];
extern struct stats max_stats;
/*
* Function types
*/
void _attach(THING **list, THING *item);
void _detach(THING **list, THING *item);
void _free_list(THING **ptr);
void addmsg(struct rogue_state *rs,char *fmt, ...);
bool add_haste(struct rogue_state *rs,bool potion);
char add_line(struct rogue_state *rs,char *fmt, char *arg);
void add_pack(struct rogue_state *rs,THING *obj, bool silent);
void add_pass(void);
void add_str(str_t *sp, int amt);
void accnt_maze(int y, int x, int ny, int nx);
void aggravate(struct rogue_state *rs);
int attack(struct rogue_state *rs,THING *mp);
void badcheck(char *name, struct obj_info *info, int bound);
void bounce(struct rogue_state *rs,THING *weap, char *mname, bool noend);
void call(struct rogue_state *rs);
void call_it(struct rogue_state *rs,struct obj_info *info);
bool cansee(struct rogue_state *rs,int y, int x);
int center(char *str);
void chg_str(int amt);
void check_level(struct rogue_state *rs);
void conn(struct rogue_state *rs,int r1, int r2);
void command(struct rogue_state *rs);
void create_obj(struct rogue_state *rs);
void current(struct rogue_state *rs,THING *cur, char *how, char *where);
void d_level(struct rogue_state *rs);
void death(struct rogue_state *rs,char monst);
char death_monst(void);
void dig(int y, int x);
void discard(THING *item);
void discovered(struct rogue_state *rs);
int dist(int y1, int x1, int y2, int x2);
int dist_cp(coord *c1, coord *c2);
int do_chase(struct rogue_state *rs,THING *th);
void do_daemons(struct rogue_state *rs,int flag);
void do_fuses(struct rogue_state *rs,int flag);
void do_maze(struct room *rp);
void do_motion(struct rogue_state *rs,THING *obj, int ydelta, int xdelta);
void do_move(struct rogue_state *rs,int dy, int dx);
void do_passages(struct rogue_state *rs);
void do_pot(struct rogue_state *rs,int type, bool knowit);
void do_rooms(struct rogue_state *rs);
void do_run(char ch);
void do_zap(struct rogue_state *rs);
void doadd(struct rogue_state *rs,char *fmt, va_list args);
void door(struct room *rm, coord *cp);
void door_open(struct rogue_state *rs,struct room *rp);
void drain(struct rogue_state *rs);
void draw_room(struct room *rp);
void drop(struct rogue_state *rs);
void eat(struct rogue_state *rs);
size_t encread(char *start, size_t size, FILE *inf);
size_t encwrite(char *start, size_t size, FILE *outf);
int endmsg(struct rogue_state *rs);
void enter_room(struct rogue_state *rs,coord *cp);
void erase_lamp(coord *pos, struct room *rp);
int exp_add(THING *tp);
void extinguish(void (*func)(struct rogue_state *rs,int));
void fall(struct rogue_state *rs,THING *obj, bool pr);
void fire_bolt(struct rogue_state *rs,coord *start, coord *dir, char *name);
char floor_at(void);
void flush_type(void);
int fight(struct rogue_state *rs,coord *mp, THING *weap, bool thrown);
void fix_stick(THING *cur);
void fuse(void (*func)(struct rogue_state *rs,int), int arg, int time, int type);
bool get_dir(struct rogue_state *rs);
int gethand(struct rogue_state *rs);
void give_pack(struct rogue_state *rs,THING *tp);
void help(struct rogue_state *rs);
void hit(struct rogue_state *rs,char *er, char *ee, bool noend);
void horiz(struct room *rp, int starty);
void leave_room(struct rogue_state *rs,coord *cp);
void lengthen(void (*func)(struct rogue_state *rs,int), int xtime);
void look(struct rogue_state *rs,bool wakeup);
int hit_monster(struct rogue_state *rs,int y, int x, THING *obj);
void identify(struct rogue_state *rs);
void illcom(struct rogue_state *rs,int ch);
void init_check(void);
void init_colors(void);
void init_materials(void);
void init_names(void);
void init_player(struct rogue_state *rs);
void init_probs(void);
void init_stones(void);
void init_weapon(THING *weap, int which);
bool inventory(struct rogue_state *rs,THING *list, int type);
void invis_on(void);
void killed(struct rogue_state *rs,THING *tp, bool pr);
void kill_daemon(void (*func)(struct rogue_state *rs,int));
bool lock_sc(void);
void miss(struct rogue_state *rs,char *er, char *ee, bool noend);
void missile(struct rogue_state *rs,int ydelta, int xdelta);
void money(struct rogue_state *rs,int value);
int move_monst(struct rogue_state *rs,THING *tp);
void move_msg(struct rogue_state *rs,THING *obj);
int msg(struct rogue_state *rs,char *fmt, ...);
void nameit(THING *obj, const char *type, const char *which, struct obj_info *op, char *(*prfunc)(THING *));
void new_level(struct rogue_state *rs);
void new_monster(struct rogue_state *rs,THING *tp, char type, coord *cp);
void numpass(int y, int x);
void option(struct rogue_state *rs);
void open_score(void);
void parse_opts(char *str);
void passnum(void);
char *pick_color(char *col);
int pick_one(struct rogue_state *rs,struct obj_info *info, int nitems);
void pick_up(struct rogue_state *rs,char ch);
void picky_inven(struct rogue_state *rs);
void pr_spec(struct obj_info *info, int nitems);
void pr_list(void);
void put_bool(void *b);
void put_inv_t(void *ip);
void put_str(void *str);
void put_things(struct rogue_state *rs);
void putpass(coord *cp);
void print_disc(struct rogue_state *rs,char);
void quaff(struct rogue_state *rs);
void raise_level(struct rogue_state *rs);
char randmonster(bool wander);
void read_scroll(struct rogue_state *rs);
void relocate(struct rogue_state *rs,THING *th, coord *new_loc);
void remove_mon(struct rogue_state *rs,coord *mp, THING *tp, bool waskill);
void reset_last(void);
bool restore(struct rogue_state *rs,char *file, char **envp);
int ring_eat(int hand);
void ring_on(struct rogue_state *rs);
void ring_off(struct rogue_state *rs);
int rnd(int range);
int rnd_room(void);
int roll(int number, int sides);
int rs_save_file(struct rogue_state *rs,FILE *savef);
int rs_restore_file(FILE *inf);
void runto(struct rogue_state *rs,coord *runner);
void rust_armor(struct rogue_state *rs,THING *arm);
int save(int which);
void save_file(struct rogue_state *rs,FILE *savef,int32_t guiflag);
void save_game(struct rogue_state *rs);
int save_throw(int which, THING *tp);
void score(struct rogue_state *rs,int amount, int flags, char monst);
void search(struct rogue_state *rs);
void set_know(THING *obj, struct obj_info *info);
void set_oldch(THING *tp, coord *cp);
void setup(void);
void shell(struct rogue_state *rs);
bool show_floor(void);
void show_map(void);
void show_win(struct rogue_state *rs,char *message);
int sign(int nm);
int spread(int nm);
void start_daemon(void (*func)(struct rogue_state *rs,int), int arg, int type);
void start_score(void);
void status(struct rogue_state *rs);
int step_ok(int ch);
void strucpy(char *s1, char *s2, int len);
int swing(int at_lvl, int op_arm, int wplus);
void take_off(struct rogue_state *rs);
void teleport(struct rogue_state *rs);
void total_winner(struct rogue_state *rs);
void thunk(struct rogue_state *rs,THING *weap, char *mname, bool noend);
void treas_room(struct rogue_state *rs);
void turnref(void);
void u_level(struct rogue_state *rs);
void uncurse(THING *obj);
void unlock_sc(void);
void vert(struct room *rp, int startx);
void wait_for(struct rogue_state *rs,int ch);
THING *wake_monster(struct rogue_state *rs,int y, int x);
void wanderer(struct rogue_state *rs);
void waste_time(struct rogue_state *rs);
void wear(struct rogue_state *rs);
void whatis(struct rogue_state *rs,bool insist, int type);
void wield(struct rogue_state *rs);
bool chase(THING *tp, coord *ee);
bool diag_ok(coord *sp, coord *ep);
bool dropcheck(struct rogue_state *rs,THING *obj);
bool fallpos(coord *pos, coord *newpos);
bool find_floor(struct room *rp, coord *cp, int limit, bool monst);
bool is_magic(THING *obj);
bool is_symlink(char *sp);
bool levit_check(struct rogue_state *rs);
bool pack_room(struct rogue_state *rs,bool from_floor, THING *obj);
bool roll_em(THING *thatt, THING *thdef, THING *weap, bool hurl);
bool see_monst(THING *mp);
bool seen_stairs(void);
bool turn_ok(int y, int x);
bool turn_see(bool turn_off);
bool is_current(struct rogue_state *rs,THING *obj);
int passwd(void);
char be_trapped(struct rogue_state *rs,coord *tc);
char floor_ch(void);
char pack_char(void);
char readchar(struct rogue_state *rs);
char rnd_thing(void);
char *charge_str(THING *obj);
char *choose_str(char *ts, char *ns);
char *inv_name(THING *obj, bool drop);
char *nullstr(THING *ignored);
char *num(int n1, int n2, char type);
char *ring_num(THING *obj);
char *set_mname(THING *tp);
char *vowelstr(char *str);
int get_bool(struct rogue_state *rs,void *vp, WINDOW *win);
int get_inv_t(struct rogue_state *rs,void *vp, WINDOW *win);
int get_num(struct rogue_state *rs,void *vp, WINDOW *win);
int get_sf(struct rogue_state *rs,void *vp, WINDOW *win);
int get_str(struct rogue_state *rs,void *vopt, WINDOW *win);
int trip_ch(int y, int x, int ch);
coord *find_dest(struct rogue_state *rs,THING *tp);
coord *rndmove(THING *who);
THING *find_obj(struct rogue_state *rs,int y, int x);
THING *get_item(struct rogue_state *rs,char *purpose, int type);
THING *leave_pack(struct rogue_state *rs,THING *obj, bool newobj, bool all);
THING *new_item(void);
THING *new_thing(struct rogue_state *rs);
void end_line(struct rogue_state *rs);
int32_t num_packitems();
void runners(struct rogue_state *rs,int);
void land(struct rogue_state *rs,int);
void visuals(struct rogue_state *rs,int);
void come_down(struct rogue_state *rs,int);
void stomach(struct rogue_state *rs,int);
void nohaste(struct rogue_state *rs,int);
void sight(struct rogue_state *rs,int);
void unconfuse(struct rogue_state *rs,int);
void rollwand(struct rogue_state *rs,int);
void unsee(struct rogue_state *rs,int);
void swander(struct rogue_state *rs,int);
void doctor(struct rogue_state *rs,int);
void playit(struct rogue_state *rs);
struct room *roomin(struct rogue_state *rs,coord *cp);
#define MAXDAEMONS 20
extern struct delayed_action {
int d_type;
void (*d_func)(struct rogue_state *rs,int);
int d_arg;
int d_time;
} d_list[MAXDAEMONS];
typedef struct {
char *st_name;
int st_value;
} STONE;
extern int total;
extern int between;
extern int group;
extern coord nh;
extern const char *rainbow[];
extern int cNCOLORS;
extern const STONE stones[];
extern int cNSTONES;
extern const char *wood[];
extern int cNWOOD;
extern const char *metal[];
extern int cNMETAL;
#endif

1060
src/cc/rogue/rogue.html Normal file

File diff suppressed because it is too large Load Diff

1060
src/cc/rogue/rogue.html.in Normal file

File diff suppressed because it is too large Load Diff

892
src/cc/rogue/rogue.me Normal file
View File

@@ -0,0 +1,892 @@
.\"
.\" @(#)rogue.me 6.2 (Berkeley) 4/28/86
.\"
.\" Rogue: Exploring the Dungeons of Doom
.\" Copyright (C) 1980-1983, 1985, 1986 Michael Toy, Ken Arnold and Glenn Wichman
.\" All rights reserved.
.\"
.\" See the file LICENSE.TXT for full copyright and licensing information.
.\"
.ds E \s-2<ESCAPE>\s0
.ds R \s-2<RETURN>\s0
.ds U \s-2UNIX\s0
.ie t .ds _ \d\(mi\u
.el .ds _ _
.de Cs
\&\\$3\*(lq\\$1\*(rq\\$2
..
.sp 5
.ce 1000
.ps +4
.vs +4p
.b
A Guide to the Dungeons of Doom
.r
.vs
.ps
.sp 2
.i
Michael C. Toy
Kenneth C. R. C. Arnold
.r
.sp 2
Computer Systems Research Group
Department of Electrical Engineering and Computer Science
University of California
Berkeley, California 94720
.sp 4
.i ABSTRACT
.ce 0
.(b I F
.bi Rogue
is a visual CRT based fantasy game
which runs under the \*U\(dg timesharing system.
.(f
\fR\(dg\*U is a trademark of Bell Laboratories\fP
.)f
This paper describes how to play rogue,
and gives a few hints
for those who might otherwise get lost in the Dungeons of Doom.
.)b
\".he '''\fBA Guide to the Dungeons of Doom\fP'
\" .fo ''- % -''
.eh 'USD:33-%''A Guide to the Dungeons of Doom'
.oh 'A Guide to the Dungeons of Doom''USD:33-%'
.sh 1 Introduction
.pp
You have just finished your years as a student at the local fighter's guild.
After much practice and sweat you have finally completed your training
and are ready to embark upon a perilous adventure.
As a test of your skills,
the local guildmasters have sent you into the Dungeons of Doom.
Your task is to return with the Amulet of Yendor.
Your reward for the completion of this task
will be a full membership in the local guild.
In addition,
you are allowed to keep all the loot you bring back from the dungeons.
.pp
In preparation for your journey,
you are given an enchanted mace,
a bow, and a quiver of arrows
taken from a dragon's hoard in the far off Dark Mountains.
You are also outfitted with elf-crafted armor
and given enough food to reach the dungeons.
You say goodbye to family and friends for what may be the last time
and head up the road.
.pp
You set out on your way to the dungeons
and after several days of uneventful travel,
you see the ancient ruins
that mark the entrance to the Dungeons of Doom.
It is late at night,
so you make camp at the entrance
and spend the night sleeping under the open skies.
In the morning you gather your weapons,
put on your armor,
eat what is almost your last food,
and enter the dungeons.
.sh 1 "What is going on here?"
.pp
You have just begun a game of rogue.
Your goal is to grab as much treasure as you can,
find the Amulet of Yendor,
and get out of the Dungeons of Doom alive.
On the screen,
a map of where you have been
and what you have seen on the current dungeon level is kept.
As you explore more of the level,
it appears on the screen in front of you.
.pp
Rogue differs from most computer fantasy games in that it is screen oriented.
Commands are all one or two keystrokes\**
.(f
\** As opposed to pseudo English sentences.
.)f
and the results of your commands
are displayed graphically on the screen rather
than being explained in words.\**
.(f
\** A minimum screen size of 24 lines by 80 columns is required.
If the screen is larger, only the 24x80 section will be used
for the map.
.)f
.pp
Another major difference between rogue and other computer fantasy games
is that once you have solved all the puzzles in a standard fantasy game,
it has lost most of its excitement and it ceases to be fun.
Rogue,
on the other hand,
generates a new dungeon every time you play it
and even the author finds it an entertaining and exciting game.
.sh 1 "What do all those things on the screen mean?"
.pp
In order to understand what is going on in rogue
you have to first get some grasp of what rogue is doing with the screen.
The rogue screen is intended
to replace the \*(lqYou can see ...\*(rq descriptions
of standard fantasy games.
Figure 1 is a sample of what a rogue screen might look like.
.(z
.hl
.nf
.TS
center;
ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce.
- - - - - - - - - - - -
| . . . . . . . . . . +
| . . @ . . . . ] . . |
| . . . . B . . . . . |
| . . . . . . . . . . |
- - - - - + - - - - - -
.TE
.ce 1000
Level: 1 Gold: 0 Hp: 12(12) Str: 16(16) Arm: 4 Exp: 1/0
Figure 1
.ce
.hl
.)z
.sh 2 "The bottom line"
.pp
At the bottom line of the screen
are a few pieces of cryptic information
describing your current status.
Here is an explanation of what these things mean:
.ip Level \w'Level\ \ 'u
This number indicates how deep you have gone in the dungeon.
It starts at one and goes up as you go deeper into the dungeon.
.ip Gold \w'Level\ \ 'u
The number of gold pieces you have managed to find
and keep with you so far.
.ip Hp \w'Level\ \ 'u
Your current and maximum health points.
Health points indicate how much damage you can take before you die.
The more you get hit in a fight,
the lower they get.
You can regain health points by resting.
The number in parentheses
is the maximum number your health points can reach.
.ip Str \w'Level\ \ 'u
Your current strength and maximum ever strength.
This can be any integer less than or equal to 31,
or greater than or equal to three.
The higher the number,
the stronger you are.
The number in the parentheses
is the maximum strength you have attained so far this game.
.ip Arm \w'Level\ \ 'u
Your current armor protection.
This number indicates how effective your armor is
in stopping blows from unfriendly creatures.
The higher this number is,
the more effective the armor.
.ip Exp \w'Level\ \ 'u
These two numbers give your current experience level
and experience points.
As you do things,
you gain experience points.
At certain experience point totals,
you gain an experience level.
The more experienced you are,
the better you are able to fight and to withstand magical attacks.
.sh 2 "The top line"
.pp
The top line of the screen is reserved
for printing messages that describe things
that are impossible to represent visually.
If you see a \*(lq--More--\*(rq on the top line,
this means that rogue wants to print another message on the screen,
but it wants to make certain
that you have read the one that is there first.
To read the next message,
just type a space.
.sh 2 "The rest of the screen"
.pp
The rest of the screen is the map of the level
as you have explored it so far.
Each symbol on the screen represents something.
Here is a list of what the various symbols mean:
.ip @
This symbol represents you, the adventurer.
.ip "-\^|"
These symbols represent the walls of rooms.
.ip +
A door to/from a room.
.ip .
The floor of a room.
.ip #
The floor of a passage between rooms.
.ip *
A pile or pot of gold.
.ip )
A weapon of some sort.
.ip ]
A piece of armor.
.ip !
A flask containing a magic potion.
.ip ?
A piece of paper, usually a magic scroll.
.ip =
A ring with magic properties
.ip /
A magical staff or wand
.ip ^
A trap, watch out for these.
.ip %
A staircase to other levels
.ip :
A piece of food.
.ip A-Z
The uppercase letters
represent the various inhabitants of the Dungeons of Doom.
Watch out, they can be nasty and vicious.
.sh 1 Commands
.pp
Commands are given to rogue by typing one or two characters.
Most commands can be preceded by a count to repeat them
(e.g. typing
.Cs 10s
will do ten searches).
Commands for which counts make no sense
have the count ignored.
To cancel a count or a prefix,
type \*E.
The list of commands is rather long,
but it can be read at any time during the game with the
.Cs ?
command.
Here it is for reference,
with a short explanation of each command.
.ip ?
The help command.
Asks for a character to give help on.
If you type a
.Cs * ,
it will list all the commands,
otherwise it will explain what the character you typed does.
.ip /
This is the \*(lqWhat is that on the screen?\*(rq command.
A
.Cs /
followed by any character that you see on the level,
will tell you what that character is.
For instance,
typing
.Cs /@
will tell you that the
.Cs @
symbol represents you, the player.
.ip "h, H, ^H"
Move left.
You move one space to the left.
If you use upper case
.Cs h ,
you will continue to move left until you run into something.
This works for all movement commands
(e.g.
.Cs L
means run in direction
.Cs l )
If you use the \*(lqcontrol\*(rq
.Cs h ,
you will continue moving in the specified direction
until you pass something interesting or run into a wall.
You should experiment with this,
since it is a very useful command,
but very difficult to describe.
This also works for all movement commands.
.ip j
Move down.
.ip k
Move up.
.ip l
Move right.
.ip y
Move diagonally up and left.
.ip u
Move diagonally up and right.
.ip b
Move diagonally down and left.
.ip n
Move diagonally down and right.
.ip t
Throw an object.
This is a prefix command.
When followed with a direction
it throws an object in the specified direction.
(e.g. type
.Cs th
to throw
something to the left.)
.ip f
Fight until someone dies.
When followed with a direction
this will force you to fight the creature in that direction
until either you or it bites the big one.
.ip m
Move onto something without picking it up.
This will move you one space in the direction you specify and,
if there is an object there you can pick up,
it won't do it.
.ip z
Zap prefix.
Point a staff or wand in a given direction
and fire it.
Even non-directional staves must be pointed in some direction
to be used.
.ip ^
Identify trap command.
If a trap is on your map
and you can't remember what type it is,
you can get rogue to remind you
by getting next to it and typing
.Cs ^
followed by the direction that would move you on top of it.
.ip s
Search for traps and secret doors.
Examine each space immediately adjacent to you
for the existence of a trap or secret door.
There is a large chance that even if there is something there,
you won't find it,
so you might have to search a while before you find something.
.ip >
Climb down a staircase to the next level.
Not surprisingly, this can only be done if you are standing on staircase.
.ip <
Climb up a staircase to the level above.
This can't be done without the Amulet of Yendor in your possession.
.ip "."
Rest.
This is the \*(lqdo nothing\*(rq command.
This is good for waiting and healing.
.ip ,
Pick up something.
This picks up whatever you are currently standing on,
if you are standing on anything at all.
.ip i
Inventory.
List what you are carrying in your pack.
.ip I
Selective inventory.
Tells you what a single item in your pack is.
.ip q
Quaff one of the potions you are carrying.
.ip r
Read one of the scrolls in your pack.
.ip e
Eat food from your pack.
.ip w
Wield a weapon.
Take a weapon out of your pack and carry it for use in combat,
replacing the one you are currently using (if any).
.ip W
Wear armor.
You can only wear one suit of armor at a time.
This takes extra time.
.ip T
Take armor off.
You can't remove armor that is cursed.
This takes extra time.
.ip P
Put on a ring.
You can wear only two rings at a time
(one on each hand).
If you aren't wearing any rings,
this command will ask you which hand you want to wear it on,
otherwise, it will place it on the unused hand.
The program assumes that you wield your sword in your right hand.
.ip R
Remove a ring.
If you are only wearing one ring,
this command takes it off.
If you are wearing two,
it will ask you which one you wish to remove,
.ip d
Drop an object.
Take something out of your pack and leave it lying on the floor.
Only one object can occupy each space.
You cannot drop a cursed object at all
if you are wielding or wearing it.
.ip c
Call an object something.
If you have a type of object in your pack
which you wish to remember something about,
you can use the call command to give a name to that type of object.
This is usually used when you figure out what a
potion, scroll, ring, or staff is
after you pick it up,
or when you want to remember
which of those swords in your pack you were wielding.
.ip D
Print out which things you've discovered something about.
This command will ask you what type of thing you are interested in.
If you type the character for a given type of object
(\fIe.g.\fP
.Cs !
for potion)
it will tell you which kinds of that type of object you've discovered
(\fIi.e.\fP, figured out what they are).
This command works for potions, scrolls, rings, and staves and wands.
.ip o
Examine and set options.
This command is further explained in the section on options.
.ip ^R
Redraws the screen.
Useful if spurious messages or transmission errors
have messed up the display.
.ip ^P
Print last message.
Useful when a message disappears before you can read it.
This only repeats the last message
that was not a mistyped command
so that you don't loose anything by accidentally typing
the wrong character instead of ^P.
.ip \*E
Cancel a command, prefix, or count.
.ip !
Escape to a shell for some commands.
.ip Q
Quit.
Leave the game.
.ip S
Save the current game in a file.
It will ask you whether you wish to use the default save file.
.i Caveat :
Rogue won't let you start up a copy of a saved game,
and it removes the save file as soon as you start up a restored game.
This is to prevent people from saving a game just before a dangerous position
and then restarting it if they die.
To restore a saved game,
give the file name as an argument to rogue.
As in
.ti +1i
.nf
% rogue \fIsave\*_file\fP
.ip
To restart from the default save file (see below),
run
.ti +1i
.nf
% rogue \-r
.ip v
Prints the program version number.
.ip )
Print the weapon you are currently wielding
.ip ]
Print the armor you are currently wearing
.ip =
Print the rings you are currently wearing
.ip @
Reprint the status line on the message line
.sh 1 Rooms
.pp
Rooms in the dungeons are either lit or dark.
If you walk into a lit room,
the entire room will be drawn on the screen as soon as you enter.
If you walk into a dark room,
it will only be displayed as you explore it.
Upon leaving a room,
all monsters inside the room
are erased from the screen.
In the darkness you can only see one space
in all directions around you.
A corridor is always dark.
.sh 1 Fighting
.pp
If you see a monster and you wish to fight it,
just attempt to run into it.
Many times a monster you find will mind its own business
unless you attack it.
It is often the case that discretion is the better part of valor.
.sh 1 "Objects you can find"
.pp
When you find something in the dungeon,
it is common to want to pick the object up.
This is accomplished in rogue by walking over the object
(unless you use the
.Cs m
prefix, see above).
If you are carrying too many things,
the program will tell you and it won't pick up the object,
otherwise it will add it to your pack
and tell you what you just picked up.
.pp
Many of the commands that operate on objects must prompt you
to find out which object you want to use.
If you change your mind and don't want to do that command after all,
just type an \*E and the command will be aborted.
.pp
Some objects, like armor and weapons,
are easily differentiated.
Others, like scrolls and potions,
are given labels which vary according to type.
During a game,
any two of the same kind of object
with the same label
are the same type.
However,
the labels will vary from game to game.
.pp
When you use one of these labeled objects,
if its effect is obvious,
rogue will remember what it is for you.
If it's effect isn't extremely obvious
you will be asked what you want to scribble on it
so you will recognize it later,
or you can use the
.Cs call
command
(see above).
.sh 2 Weapons
.pp
Some weapons,
like arrows,
come in bunches,
but most come one at a time.
In order to use a weapon,
you must wield it.
To fire an arrow out of a bow,
you must first wield the bow,
then throw the arrow.
You can only wield one weapon at a time,
but you can't change weapons if the one
you are currently wielding is cursed.
The commands to use weapons are
.Cs w
(wield)
and
.Cs t
(throw).
.sh 2 Armor
.pp
There are various sorts of armor lying around in the dungeon.
Some of it is enchanted,
some is cursed,
and some is just normal.
Different armor types have different armor protection.
The higher the armor protection,
the more protection the armor affords against the blows of monsters.
Here is a list of the various armor types and their normal armor protection:
.(b
.TS
box center;
l r.
\ \ \fIType Protection\fP
None 0
Leather armor 2
Studded leather / Ring mail 3
Scale mail 4
Chain mail 5
Banded mail / Splint mail 6
Plate mail 7
.TE
.)b
.lp
If a piece of armor is enchanted,
its armor protection will be higher than normal.
If a suit of armor is cursed,
its armor protection will be lower,
and you will not be able to remove it.
However, not all armor with a protection that is lower than normal is cursed.
.pp
The commands to use weapons are
.Cs W
(wear)
and
.Cs T
(take off).
.sh 2 Scrolls
.pp
Scrolls come with titles in an unknown tongue\**.
.(f
\** Actually, it's a dialect spoken only by the twenty-seven members
of a tribe in Outer Mongolia,
but you're not supposed to
.i know
that.
.)f
After you read a scroll,
it disappears from your pack.
The command to use a scroll is
.Cs r
(read).
.sh 2 Potions
.pp
Potions are labeled by the color of the liquid inside the flask.
They disappear after being quaffed.
The command to use a scroll is
.Cs q
(quaff).
.sh 2 "Staves and Wands"
.pp
Staves and wands do the same kinds of things.
Staves are identified by a type of wood;
wands by a type of metal or bone.
They are generally things you want to do to something
over a long distance,
so you must point them at what you wish to affect
to use them.
Some staves are not affected by the direction they are pointed, though.
Staves come with multiple magic charges,
the number being random,
and when they are used up,
the staff is just a piece of wood or metal.
.pp
The command to use a wand or staff is
.Cs z
(zap)
.sh 2 Rings
.pp
Rings are very useful items,
since they are relatively permanent magic,
unlike the usually fleeting effects of potions, scrolls, and staves.
Of course,
the bad rings are also more powerful.
Most rings also cause you to use up food more rapidly,
the rate varying with the type of ring.
Rings are differentiated by their stone settings.
The commands to use rings are
.Cs P
(put on)
and
.Cs R
(remove).
.sh 2 Food
.pp
Food is necessary to keep you going.
If you go too long without eating you will faint,
and eventually die of starvation.
The command to use food is
.Cs e
(eat).
.sh 1 Options
.pp
Due to variations in personal tastes
and conceptions of the way rogue should do things,
there are a set of options you can set
that cause rogue to behave in various different ways.
.sh 2 "Setting the options"
.pp
There are two ways to set the options.
The first is with the
.Cs o
command of rogue;
the second is with the
.Cs ROGUEOPTS
environment variable\**.
.(f
\** On Version 6 systems,
there is no equivalent of the ROGUEOPTS feature.
.br
.)f
.br
.sh 3 "Using the `o' command"
.pp
When you type
.Cs o
in rogue,
it clears the screen
and displays the current settings for all the options.
It then places the cursor by the value of the first option
and waits for you to type.
You can type a \*R
which means to go to the next option,
a
.Cs \-
which means to go to the previous option,
an \*E
which means to return to the game,
or you can give the option a value.
For boolean options this merely involves typing
.Cs t
for true or
.Cs f
for false.
For string options,
type the new value followed by a \*R.
.sh 3 "Using the ROGUEOPTS variable"
.pp
The ROGUEOPTS variable is a string
containing a comma separated list of initial values
for the various options.
Boolean variables can be turned on by listing their name
or turned off by putting a
.Cs no
in front of the name.
Thus to set up an environment variable so that
.b jump
is on,
.b terse
is off,
and the
.b name
is set to \*(lqBlue Meanie\*(rq,
use the command
.nf
.ti +3n
% setenv ROGUEOPTS "jump,noterse,name=Blue Meanie"\**
.fi
.(f
\**
For those of you who use the Bourne shell sh (1), the commands would be
.in +3
.nf
$ ROGUEOPTS="jump,noterse,name=Blue Meanie"
$ export ROGUEOPTS
.fi
.in +0
.)f
.sh 2 "Option list"
.pp
Here is a list of the options
and an explanation of what each one is for.
The default value for each is enclosed in square brackets.
For character string options,
input over fifty characters will be ignored.
.ip "\fBterse\fP [\fI\^noterse\^\fP]"
Useful for those who are tired of the sometimes lengthy messages of rogue.
This is a useful option for playing on slow terminals,
so this option defaults to
.i terse
if you
are on a slow (1200 baud or under) terminal.
.ip "\fBjump\fP [\fI\^nojump\^\fP]"
If this option is set,
running moves will not be displayed
until you reach the end of the move.
This saves considerable cpu and display time.
This option defaults to
.i jump
if you are using a slow terminal.
.ip "\fBflush\fP [\fI\^noflush\^\fP]"
All typeahead is thrown away after each round of battle.
This is useful for those who type far ahead
and then watch in dismay as a Bat kills them.
.ip "\fBseefloor\fP [\fI\^seefloor\^\fP]"
Display the floor around you on the screen
as you move through dark rooms.
Due to the amount of characters generated,
this option defaults to
.i noseefloor
if you are using a slow terminal.
.ip "\fBpassgo\fP [\fI\^nopassgo\^\fP]"
Follow turnings in passageways.
If you run in a passage
and you run into stone or a wall,
rogue will see if it can turn to the right or left.
If it can only turn one way,
it will turn that way.
If it can turn either or neither,
it will stop.
This algorithm can sometimes lead to slightly confusing occurrences
which is why it defaults to \fInopassgo\fP.
.ip "\fBtombstone\fP [\fI\^tombstone\^\fP]"
Print out the tombstone at the end if you get killed.
This is nice but slow, so you can turn it off if you like.
.ip "\fBinven\fP [\fI\^overwrite\^\fP]"
Inventory type.
This can have one of three values:
.i overwrite ,
.i slow ,
or
.i clear .
With
.i overwrite
the top lines of the map are overwritten
with the list
when inventory is requested
or when
\*(lqWhich item do you wish to \fB. . .\fP? \*(rq questions
are answered with a
.Cs * .
However, if the list is longer than a screenful,
the screen is cleared.
With
.i slow ,
lists are displayed one item at a time on the top of the screen,
and with
.i clear ,
the screen is cleared,
the list is displayed,
and then the dungeon level is re-displayed.
Due to speed considerations,
.i clear
is the default for terminals without
clear-to-end-of-line capabilities.
.ip "\fBname\fP [account name]"
This is the name of your character.
It is used if you get on the top ten scorer's list.
.ip "\fBfruit\fP [\fI\^slime-mold\^\fP]"
This should hold the name of a fruit that you enjoy eating.
It is basically a whimsey that rogue uses in a couple of places.
.ip "\fBfile\fP [\fI\^~/rogue.save\^\fP]"
The default file name for saving the game.
If your phone is hung up by accident,
rogue will automatically save the game in this file.
The file name may start with the special character
.Cs ~
which expands to be your home directory.
.sh 1 Scoring
.pp
Rogue usually maintains a list
of the top scoring people or scores on your machine.
Depending on how it is set up,
it can post either the top scores
or the top players.
In the latter case,
each account on the machine
can post only one non-winning score on this list.
If you score higher than someone else on this list,
or better your previous score on the list,
you will be inserted in the proper place
under your current name.
How many scores are kept
can also be set up by whoever installs it on your machine.
.pp
If you quit the game, you get out with all of your gold intact.
If, however, you get killed in the Dungeons of Doom,
your body is forwarded to your next-of-kin,
along with 90% of your gold;
ten percent of your gold is kept by the Dungeons' wizard as a fee\**.
.(f
\** The Dungeon's wizard is named Wally the Wonder Badger.
Invocations should be accompanied by a sizable donation.
.)f
This should make you consider whether you want to take one last hit
at that monster and possibly live,
or quit and thus stop with whatever you have.
If you quit, you do get all your gold,
but if you swing and live, you might find more.
.pp
If you just want to see what the current top players/games list is,
you can type
.ti +1i
.nf
% rogue \-s
.br
.sh 1 Acknowledgements
.pp
Rogue was originally conceived of by Glenn Wichman and Michael Toy.
Ken Arnold and Michael Toy then smoothed out the user interface,
and added jillions of new features.
We would like to thank
Bob Arnold,
Michelle Busch,
Andy Hatcher,
Kipp Hickman,
Mark Horton,
Daniel Jensen,
Bill Joy,
Joe Kalash,
Steve Maurer,
Marty McNary,
Jan Miller,
and
Scott Nelson
for their ideas and assistance;
and also the teeming multitudes
who graciously ignored work, school, and social life to play rogue
and send us bugs, complaints, suggestions, and just plain flames.
And also Mom.

892
src/cc/rogue/rogue.me.in Normal file
View File

@@ -0,0 +1,892 @@
.\"
.\" @(#)rogue.me 6.2 (Berkeley) 4/28/86
.\"
.\" Rogue: Exploring the Dungeons of Doom
.\" Copyright (C) 1980-1983, 1985, 1986 Michael Toy, Ken Arnold and Glenn Wichman
.\" All rights reserved.
.\"
.\" See the file LICENSE.TXT for full copyright and licensing information.
.\"
.ds E \s-2<ESCAPE>\s0
.ds R \s-2<RETURN>\s0
.ds U \s-2UNIX\s0
.ie t .ds _ \d\(mi\u
.el .ds _ _
.de Cs
\&\\$3\*(lq\\$1\*(rq\\$2
..
.sp 5
.ce 1000
.ps +4
.vs +4p
.b
A Guide to the Dungeons of Doom
.r
.vs
.ps
.sp 2
.i
Michael C. Toy
Kenneth C. R. C. Arnold
.r
.sp 2
Computer Systems Research Group
Department of Electrical Engineering and Computer Science
University of California
Berkeley, California 94720
.sp 4
.i ABSTRACT
.ce 0
.(b I F
.bi Rogue
is a visual CRT based fantasy game
which runs under the \*U\(dg timesharing system.
.(f
\fR\(dg\*U is a trademark of Bell Laboratories\fP
.)f
This paper describes how to play rogue,
and gives a few hints
for those who might otherwise get lost in the Dungeons of Doom.
.)b
\".he '''\fBA Guide to the Dungeons of Doom\fP'
\" .fo ''- % -''
.eh 'USD:33-%''A Guide to the Dungeons of Doom'
.oh 'A Guide to the Dungeons of Doom''USD:33-%'
.sh 1 Introduction
.pp
You have just finished your years as a student at the local fighter's guild.
After much practice and sweat you have finally completed your training
and are ready to embark upon a perilous adventure.
As a test of your skills,
the local guildmasters have sent you into the Dungeons of Doom.
Your task is to return with the Amulet of Yendor.
Your reward for the completion of this task
will be a full membership in the local guild.
In addition,
you are allowed to keep all the loot you bring back from the dungeons.
.pp
In preparation for your journey,
you are given an enchanted mace,
a bow, and a quiver of arrows
taken from a dragon's hoard in the far off Dark Mountains.
You are also outfitted with elf-crafted armor
and given enough food to reach the dungeons.
You say goodbye to family and friends for what may be the last time
and head up the road.
.pp
You set out on your way to the dungeons
and after several days of uneventful travel,
you see the ancient ruins
that mark the entrance to the Dungeons of Doom.
It is late at night,
so you make camp at the entrance
and spend the night sleeping under the open skies.
In the morning you gather your weapons,
put on your armor,
eat what is almost your last food,
and enter the dungeons.
.sh 1 "What is going on here?"
.pp
You have just begun a game of rogue.
Your goal is to grab as much treasure as you can,
find the Amulet of Yendor,
and get out of the Dungeons of Doom alive.
On the screen,
a map of where you have been
and what you have seen on the current dungeon level is kept.
As you explore more of the level,
it appears on the screen in front of you.
.pp
Rogue differs from most computer fantasy games in that it is screen oriented.
Commands are all one or two keystrokes\**
.(f
\** As opposed to pseudo English sentences.
.)f
and the results of your commands
are displayed graphically on the screen rather
than being explained in words.\**
.(f
\** A minimum screen size of 24 lines by 80 columns is required.
If the screen is larger, only the 24x80 section will be used
for the map.
.)f
.pp
Another major difference between rogue and other computer fantasy games
is that once you have solved all the puzzles in a standard fantasy game,
it has lost most of its excitement and it ceases to be fun.
Rogue,
on the other hand,
generates a new dungeon every time you play it
and even the author finds it an entertaining and exciting game.
.sh 1 "What do all those things on the screen mean?"
.pp
In order to understand what is going on in rogue
you have to first get some grasp of what rogue is doing with the screen.
The rogue screen is intended
to replace the \*(lqYou can see ...\*(rq descriptions
of standard fantasy games.
Figure 1 is a sample of what a rogue screen might look like.
.(z
.hl
.nf
.TS
center;
ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce0 ce.
- - - - - - - - - - - -
| . . . . . . . . . . +
| . . @ . . . . ] . . |
| . . . . B . . . . . |
| . . . . . . . . . . |
- - - - - + - - - - - -
.TE
.ce 1000
Level: 1 Gold: 0 Hp: 12(12) Str: 16(16) Arm: 4 Exp: 1/0
Figure 1
.ce
.hl
.)z
.sh 2 "The bottom line"
.pp
At the bottom line of the screen
are a few pieces of cryptic information
describing your current status.
Here is an explanation of what these things mean:
.ip Level \w'Level\ \ 'u
This number indicates how deep you have gone in the dungeon.
It starts at one and goes up as you go deeper into the dungeon.
.ip Gold \w'Level\ \ 'u
The number of gold pieces you have managed to find
and keep with you so far.
.ip Hp \w'Level\ \ 'u
Your current and maximum health points.
Health points indicate how much damage you can take before you die.
The more you get hit in a fight,
the lower they get.
You can regain health points by resting.
The number in parentheses
is the maximum number your health points can reach.
.ip Str \w'Level\ \ 'u
Your current strength and maximum ever strength.
This can be any integer less than or equal to 31,
or greater than or equal to three.
The higher the number,
the stronger you are.
The number in the parentheses
is the maximum strength you have attained so far this game.
.ip Arm \w'Level\ \ 'u
Your current armor protection.
This number indicates how effective your armor is
in stopping blows from unfriendly creatures.
The higher this number is,
the more effective the armor.
.ip Exp \w'Level\ \ 'u
These two numbers give your current experience level
and experience points.
As you do things,
you gain experience points.
At certain experience point totals,
you gain an experience level.
The more experienced you are,
the better you are able to fight and to withstand magical attacks.
.sh 2 "The top line"
.pp
The top line of the screen is reserved
for printing messages that describe things
that are impossible to represent visually.
If you see a \*(lq--More--\*(rq on the top line,
this means that rogue wants to print another message on the screen,
but it wants to make certain
that you have read the one that is there first.
To read the next message,
just type a space.
.sh 2 "The rest of the screen"
.pp
The rest of the screen is the map of the level
as you have explored it so far.
Each symbol on the screen represents something.
Here is a list of what the various symbols mean:
.ip @
This symbol represents you, the adventurer.
.ip "-\^|"
These symbols represent the walls of rooms.
.ip +
A door to/from a room.
.ip .
The floor of a room.
.ip #
The floor of a passage between rooms.
.ip *
A pile or pot of gold.
.ip )
A weapon of some sort.
.ip ]
A piece of armor.
.ip !
A flask containing a magic potion.
.ip ?
A piece of paper, usually a magic scroll.
.ip =
A ring with magic properties
.ip /
A magical staff or wand
.ip ^
A trap, watch out for these.
.ip %
A staircase to other levels
.ip :
A piece of food.
.ip A-Z
The uppercase letters
represent the various inhabitants of the Dungeons of Doom.
Watch out, they can be nasty and vicious.
.sh 1 Commands
.pp
Commands are given to rogue by typing one or two characters.
Most commands can be preceded by a count to repeat them
(e.g. typing
.Cs 10s
will do ten searches).
Commands for which counts make no sense
have the count ignored.
To cancel a count or a prefix,
type \*E.
The list of commands is rather long,
but it can be read at any time during the game with the
.Cs ?
command.
Here it is for reference,
with a short explanation of each command.
.ip ?
The help command.
Asks for a character to give help on.
If you type a
.Cs * ,
it will list all the commands,
otherwise it will explain what the character you typed does.
.ip /
This is the \*(lqWhat is that on the screen?\*(rq command.
A
.Cs /
followed by any character that you see on the level,
will tell you what that character is.
For instance,
typing
.Cs /@
will tell you that the
.Cs @
symbol represents you, the player.
.ip "h, H, ^H"
Move left.
You move one space to the left.
If you use upper case
.Cs h ,
you will continue to move left until you run into something.
This works for all movement commands
(e.g.
.Cs L
means run in direction
.Cs l )
If you use the \*(lqcontrol\*(rq
.Cs h ,
you will continue moving in the specified direction
until you pass something interesting or run into a wall.
You should experiment with this,
since it is a very useful command,
but very difficult to describe.
This also works for all movement commands.
.ip j
Move down.
.ip k
Move up.
.ip l
Move right.
.ip y
Move diagonally up and left.
.ip u
Move diagonally up and right.
.ip b
Move diagonally down and left.
.ip n
Move diagonally down and right.
.ip t
Throw an object.
This is a prefix command.
When followed with a direction
it throws an object in the specified direction.
(e.g. type
.Cs th
to throw
something to the left.)
.ip f
Fight until someone dies.
When followed with a direction
this will force you to fight the creature in that direction
until either you or it bites the big one.
.ip m
Move onto something without picking it up.
This will move you one space in the direction you specify and,
if there is an object there you can pick up,
it won't do it.
.ip z
Zap prefix.
Point a staff or wand in a given direction
and fire it.
Even non-directional staves must be pointed in some direction
to be used.
.ip ^
Identify trap command.
If a trap is on your map
and you can't remember what type it is,
you can get rogue to remind you
by getting next to it and typing
.Cs ^
followed by the direction that would move you on top of it.
.ip s
Search for traps and secret doors.
Examine each space immediately adjacent to you
for the existence of a trap or secret door.
There is a large chance that even if there is something there,
you won't find it,
so you might have to search a while before you find something.
.ip >
Climb down a staircase to the next level.
Not surprisingly, this can only be done if you are standing on staircase.
.ip <
Climb up a staircase to the level above.
This can't be done without the Amulet of Yendor in your possession.
.ip "."
Rest.
This is the \*(lqdo nothing\*(rq command.
This is good for waiting and healing.
.ip ,
Pick up something.
This picks up whatever you are currently standing on,
if you are standing on anything at all.
.ip i
Inventory.
List what you are carrying in your pack.
.ip I
Selective inventory.
Tells you what a single item in your pack is.
.ip q
Quaff one of the potions you are carrying.
.ip r
Read one of the scrolls in your pack.
.ip e
Eat food from your pack.
.ip w
Wield a weapon.
Take a weapon out of your pack and carry it for use in combat,
replacing the one you are currently using (if any).
.ip W
Wear armor.
You can only wear one suit of armor at a time.
This takes extra time.
.ip T
Take armor off.
You can't remove armor that is cursed.
This takes extra time.
.ip P
Put on a ring.
You can wear only two rings at a time
(one on each hand).
If you aren't wearing any rings,
this command will ask you which hand you want to wear it on,
otherwise, it will place it on the unused hand.
The program assumes that you wield your sword in your right hand.
.ip R
Remove a ring.
If you are only wearing one ring,
this command takes it off.
If you are wearing two,
it will ask you which one you wish to remove,
.ip d
Drop an object.
Take something out of your pack and leave it lying on the floor.
Only one object can occupy each space.
You cannot drop a cursed object at all
if you are wielding or wearing it.
.ip c
Call an object something.
If you have a type of object in your pack
which you wish to remember something about,
you can use the call command to give a name to that type of object.
This is usually used when you figure out what a
potion, scroll, ring, or staff is
after you pick it up,
or when you want to remember
which of those swords in your pack you were wielding.
.ip D
Print out which things you've discovered something about.
This command will ask you what type of thing you are interested in.
If you type the character for a given type of object
(\fIe.g.\fP
.Cs !
for potion)
it will tell you which kinds of that type of object you've discovered
(\fIi.e.\fP, figured out what they are).
This command works for potions, scrolls, rings, and staves and wands.
.ip o
Examine and set options.
This command is further explained in the section on options.
.ip ^R
Redraws the screen.
Useful if spurious messages or transmission errors
have messed up the display.
.ip ^P
Print last message.
Useful when a message disappears before you can read it.
This only repeats the last message
that was not a mistyped command
so that you don't loose anything by accidentally typing
the wrong character instead of ^P.
.ip \*E
Cancel a command, prefix, or count.
.ip !
Escape to a shell for some commands.
.ip Q
Quit.
Leave the game.
.ip S
Save the current game in a file.
It will ask you whether you wish to use the default save file.
.i Caveat :
Rogue won't let you start up a copy of a saved game,
and it removes the save file as soon as you start up a restored game.
This is to prevent people from saving a game just before a dangerous position
and then restarting it if they die.
To restore a saved game,
give the file name as an argument to rogue.
As in
.ti +1i
.nf
% rogue \fIsave\*_file\fP
.ip
To restart from the default save file (see below),
run
.ti +1i
.nf
% rogue \-r
.ip v
Prints the program version number.
.ip )
Print the weapon you are currently wielding
.ip ]
Print the armor you are currently wearing
.ip =
Print the rings you are currently wearing
.ip @
Reprint the status line on the message line
.sh 1 Rooms
.pp
Rooms in the dungeons are either lit or dark.
If you walk into a lit room,
the entire room will be drawn on the screen as soon as you enter.
If you walk into a dark room,
it will only be displayed as you explore it.
Upon leaving a room,
all monsters inside the room
are erased from the screen.
In the darkness you can only see one space
in all directions around you.
A corridor is always dark.
.sh 1 Fighting
.pp
If you see a monster and you wish to fight it,
just attempt to run into it.
Many times a monster you find will mind its own business
unless you attack it.
It is often the case that discretion is the better part of valor.
.sh 1 "Objects you can find"
.pp
When you find something in the dungeon,
it is common to want to pick the object up.
This is accomplished in rogue by walking over the object
(unless you use the
.Cs m
prefix, see above).
If you are carrying too many things,
the program will tell you and it won't pick up the object,
otherwise it will add it to your pack
and tell you what you just picked up.
.pp
Many of the commands that operate on objects must prompt you
to find out which object you want to use.
If you change your mind and don't want to do that command after all,
just type an \*E and the command will be aborted.
.pp
Some objects, like armor and weapons,
are easily differentiated.
Others, like scrolls and potions,
are given labels which vary according to type.
During a game,
any two of the same kind of object
with the same label
are the same type.
However,
the labels will vary from game to game.
.pp
When you use one of these labeled objects,
if its effect is obvious,
rogue will remember what it is for you.
If it's effect isn't extremely obvious
you will be asked what you want to scribble on it
so you will recognize it later,
or you can use the
.Cs call
command
(see above).
.sh 2 Weapons
.pp
Some weapons,
like arrows,
come in bunches,
but most come one at a time.
In order to use a weapon,
you must wield it.
To fire an arrow out of a bow,
you must first wield the bow,
then throw the arrow.
You can only wield one weapon at a time,
but you can't change weapons if the one
you are currently wielding is cursed.
The commands to use weapons are
.Cs w
(wield)
and
.Cs t
(throw).
.sh 2 Armor
.pp
There are various sorts of armor lying around in the dungeon.
Some of it is enchanted,
some is cursed,
and some is just normal.
Different armor types have different armor protection.
The higher the armor protection,
the more protection the armor affords against the blows of monsters.
Here is a list of the various armor types and their normal armor protection:
.(b
.TS
box center;
l r.
\ \ \fIType Protection\fP
None 0
Leather armor 2
Studded leather / Ring mail 3
Scale mail 4
Chain mail 5
Banded mail / Splint mail 6
Plate mail 7
.TE
.)b
.lp
If a piece of armor is enchanted,
its armor protection will be higher than normal.
If a suit of armor is cursed,
its armor protection will be lower,
and you will not be able to remove it.
However, not all armor with a protection that is lower than normal is cursed.
.pp
The commands to use weapons are
.Cs W
(wear)
and
.Cs T
(take off).
.sh 2 Scrolls
.pp
Scrolls come with titles in an unknown tongue\**.
.(f
\** Actually, it's a dialect spoken only by the twenty-seven members
of a tribe in Outer Mongolia,
but you're not supposed to
.i know
that.
.)f
After you read a scroll,
it disappears from your pack.
The command to use a scroll is
.Cs r
(read).
.sh 2 Potions
.pp
Potions are labeled by the color of the liquid inside the flask.
They disappear after being quaffed.
The command to use a scroll is
.Cs q
(quaff).
.sh 2 "Staves and Wands"
.pp
Staves and wands do the same kinds of things.
Staves are identified by a type of wood;
wands by a type of metal or bone.
They are generally things you want to do to something
over a long distance,
so you must point them at what you wish to affect
to use them.
Some staves are not affected by the direction they are pointed, though.
Staves come with multiple magic charges,
the number being random,
and when they are used up,
the staff is just a piece of wood or metal.
.pp
The command to use a wand or staff is
.Cs z
(zap)
.sh 2 Rings
.pp
Rings are very useful items,
since they are relatively permanent magic,
unlike the usually fleeting effects of potions, scrolls, and staves.
Of course,
the bad rings are also more powerful.
Most rings also cause you to use up food more rapidly,
the rate varying with the type of ring.
Rings are differentiated by their stone settings.
The commands to use rings are
.Cs P
(put on)
and
.Cs R
(remove).
.sh 2 Food
.pp
Food is necessary to keep you going.
If you go too long without eating you will faint,
and eventually die of starvation.
The command to use food is
.Cs e
(eat).
.sh 1 Options
.pp
Due to variations in personal tastes
and conceptions of the way rogue should do things,
there are a set of options you can set
that cause rogue to behave in various different ways.
.sh 2 "Setting the options"
.pp
There are two ways to set the options.
The first is with the
.Cs o
command of rogue;
the second is with the
.Cs ROGUEOPTS
environment variable\**.
.(f
\** On Version 6 systems,
there is no equivalent of the ROGUEOPTS feature.
.br
.)f
.br
.sh 3 "Using the `o' command"
.pp
When you type
.Cs o
in rogue,
it clears the screen
and displays the current settings for all the options.
It then places the cursor by the value of the first option
and waits for you to type.
You can type a \*R
which means to go to the next option,
a
.Cs \-
which means to go to the previous option,
an \*E
which means to return to the game,
or you can give the option a value.
For boolean options this merely involves typing
.Cs t
for true or
.Cs f
for false.
For string options,
type the new value followed by a \*R.
.sh 3 "Using the ROGUEOPTS variable"
.pp
The ROGUEOPTS variable is a string
containing a comma separated list of initial values
for the various options.
Boolean variables can be turned on by listing their name
or turned off by putting a
.Cs no
in front of the name.
Thus to set up an environment variable so that
.b jump
is on,
.b terse
is off,
and the
.b name
is set to \*(lqBlue Meanie\*(rq,
use the command
.nf
.ti +3n
% setenv ROGUEOPTS "jump,noterse,name=Blue Meanie"\**
.fi
.(f
\**
For those of you who use the Bourne shell sh (1), the commands would be
.in +3
.nf
$ ROGUEOPTS="jump,noterse,name=Blue Meanie"
$ export ROGUEOPTS
.fi
.in +0
.)f
.sh 2 "Option list"
.pp
Here is a list of the options
and an explanation of what each one is for.
The default value for each is enclosed in square brackets.
For character string options,
input over fifty characters will be ignored.
.ip "\fBterse\fP [\fI\^noterse\^\fP]"
Useful for those who are tired of the sometimes lengthy messages of rogue.
This is a useful option for playing on slow terminals,
so this option defaults to
.i terse
if you
are on a slow (1200 baud or under) terminal.
.ip "\fBjump\fP [\fI\^nojump\^\fP]"
If this option is set,
running moves will not be displayed
until you reach the end of the move.
This saves considerable cpu and display time.
This option defaults to
.i jump
if you are using a slow terminal.
.ip "\fBflush\fP [\fI\^noflush\^\fP]"
All typeahead is thrown away after each round of battle.
This is useful for those who type far ahead
and then watch in dismay as a Bat kills them.
.ip "\fBseefloor\fP [\fI\^seefloor\^\fP]"
Display the floor around you on the screen
as you move through dark rooms.
Due to the amount of characters generated,
this option defaults to
.i noseefloor
if you are using a slow terminal.
.ip "\fBpassgo\fP [\fI\^nopassgo\^\fP]"
Follow turnings in passageways.
If you run in a passage
and you run into stone or a wall,
rogue will see if it can turn to the right or left.
If it can only turn one way,
it will turn that way.
If it can turn either or neither,
it will stop.
This algorithm can sometimes lead to slightly confusing occurrences
which is why it defaults to \fInopassgo\fP.
.ip "\fBtombstone\fP [\fI\^tombstone\^\fP]"
Print out the tombstone at the end if you get killed.
This is nice but slow, so you can turn it off if you like.
.ip "\fBinven\fP [\fI\^overwrite\^\fP]"
Inventory type.
This can have one of three values:
.i overwrite ,
.i slow ,
or
.i clear .
With
.i overwrite
the top lines of the map are overwritten
with the list
when inventory is requested
or when
\*(lqWhich item do you wish to \fB. . .\fP? \*(rq questions
are answered with a
.Cs * .
However, if the list is longer than a screenful,
the screen is cleared.
With
.i slow ,
lists are displayed one item at a time on the top of the screen,
and with
.i clear ,
the screen is cleared,
the list is displayed,
and then the dungeon level is re-displayed.
Due to speed considerations,
.i clear
is the default for terminals without
clear-to-end-of-line capabilities.
.ip "\fBname\fP [account name]"
This is the name of your character.
It is used if you get on the top ten scorer's list.
.ip "\fBfruit\fP [\fI\^slime-mold\^\fP]"
This should hold the name of a fruit that you enjoy eating.
It is basically a whimsey that rogue uses in a couple of places.
.ip "\fBfile\fP [\fI\^~/rogue.save\^\fP]"
The default file name for saving the game.
If your phone is hung up by accident,
rogue will automatically save the game in this file.
The file name may start with the special character
.Cs ~
which expands to be your home directory.
.sh 1 Scoring
.pp
Rogue usually maintains a list
of the top scoring people or scores on your machine.
Depending on how it is set up,
it can post either the top scores
or the top players.
In the latter case,
each account on the machine
can post only one non-winning score on this list.
If you score higher than someone else on this list,
or better your previous score on the list,
you will be inserted in the proper place
under your current name.
How many scores are kept
can also be set up by whoever installs it on your machine.
.pp
If you quit the game, you get out with all of your gold intact.
If, however, you get killed in the Dungeons of Doom,
your body is forwarded to your next-of-kin,
along with 90% of your gold;
ten percent of your gold is kept by the Dungeons' wizard as a fee\**.
.(f
\** The Dungeon's wizard is named Wally the Wonder Badger.
Invocations should be accompanied by a sizable donation.
.)f
This should make you consider whether you want to take one last hit
at that monster and possibly live,
or quit and thus stop with whatever you have.
If you quit, you do get all your gold,
but if you swing and live, you might find more.
.pp
If you just want to see what the current top players/games list is,
you can type
.ti +1i
.nf
% @PROGRAM@ \-s
.br
.sh 1 Acknowledgements
.pp
Rogue was originally conceived of by Glenn Wichman and Michael Toy.
Ken Arnold and Michael Toy then smoothed out the user interface,
and added jillions of new features.
We would like to thank
Bob Arnold,
Michelle Busch,
Andy Hatcher,
Kipp Hickman,
Mark Horton,
Daniel Jensen,
Bill Joy,
Joe Kalash,
Steve Maurer,
Marty McNary,
Jan Miller,
and
Scott Nelson
for their ideas and assistance;
and also the teeming multitudes
who graciously ignored work, school, and social life to play rogue
and send us bugs, complaints, suggestions, and just plain flames.
And also Mom.

BIN
src/cc/rogue/rogue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

107
src/cc/rogue/rogue.spec Normal file
View File

@@ -0,0 +1,107 @@
Name: rogue
Version: 5.4.4
Release: 1%{?dist}
Summary: The original graphical adventure game
Group: Amusements/Games
License: BSD
URL: http://rogue.rogueforge.net/
Source0: http://rogue.rogueforge.net/files/rogue5.4/rogue5.4.4-src.tar.gz
Source1: rogue.desktop
Source2: rogue.png
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: desktop-file-utils
BuildRequires: ncurses-devel
%description
The one, the only, the original graphical adventure game that spawned
an entire genre.
%prep
%setup -q -n %{name}%{version}
%build
%configure --enable-setgid=games --enable-scorefile=%{_var}/games/roguelike/rogue54.scr --enable-lockfile=%{_var}/games/roguelike/rogue54.lck
make %{_smp_mflags}
%install
rm -rf $RPM_BUILD_ROOT
make install DESTDIR=$RPM_BUILD_ROOT
desktop-file-install --vendor fedora \
--dir ${RPM_BUILD_ROOT}%{_datadir}/applications \
%{SOURCE1}
mkdir -p $RPM_BUILD_ROOT/%{_datadir}/icons/hicolor/32x32/apps/
install -p -m 644 %{SOURCE2} $RPM_BUILD_ROOT/%{_datadir}/icons/hicolor/32x32/apps/
%clean
rm -rf $RPM_BUILD_ROOT
%post
touch --no-create %{_datadir}/icons/hicolor || :
if [ -x %{_bindir}/gtk-update-icon-cache ]; then
%{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :
fi
%postun
touch --no-create %{_datadir}/icons/hicolor || :
if [ -x %{_bindir}/gtk-update-icon-cache ]; then
%{_bindir}/gtk-update-icon-cache --quiet %{_datadir}/icons/hicolor || :
fi
%files
%defattr(-,root,root,-)
%attr(2755,games,games) %{_bindir}/rogue
%{_mandir}/man6/rogue.6.gz
%{_datadir}/applications/fedora-%{name}.desktop
%{_datadir}/icons/hicolor/32x32/apps/rogue.png
%dir %attr(0775,games,games) %{_var}/games/roguelike
%config(noreplace) %attr(0664,games,games) %{_var}/games/roguelike/rogue54.scr
%doc %{_docdir}/%{name}-%{version}
%changelog
* Sun Sep 2 2007 Wart <wart at kobold.org> 5.4.4-1
- Update to 5.4.4
* Mon Aug 20 2007 Wart <wart at kobold.org> 5.4.3-1
- Update to 5.4.3
* Sun Jul 15 2007 Wart <wart at kobold.org> 5.4.2-9
- New upstream home page and download URL
- Add patch when reading long values from the save file on 64-bit arch
(BZ #248283)
- Add patch removing many compiler warnings
- Use proper version in the .desktop file
* Sat Mar 3 2007 Wart <wart at kobold.org> 5.4.2-8
- Use better sourceforge download url
- Use more precise desktop file categories
* Mon Aug 28 2006 Wart <wart at kobold.org> 5.4.2-7
- Rebuild for Fedora Extras
* Tue May 16 2006 Wart <wart at kobold.org> 5.4.2-6
- Added empty initial scoreboard file.
* Mon May 15 2006 Wart <wart at kobold.org> 5.4.2-5
- Better setuid/setgid handling (again) (BZ #187392)
* Thu Mar 30 2006 Wart <wart at kobold.org> 5.4.2-4
- Better setuid/setgid handling (BZ #187392)
- Resize desktop icon to match directory name
* Mon Mar 13 2006 Wart <wart at kobold.org> 5.4.2-3
- Added icon for .desktop file.
* Sun Mar 12 2006 Wart <wart at kobold.org> 5.4.2-2
- Added missing BR: ncurses-devel, desktop-file-utils
* Sat Feb 25 2006 Wart <wart at kobold.org> 5.4.2-1
- Initial spec file.

19
src/cc/rogue/rogue54.sln Normal file
View File

@@ -0,0 +1,19 @@
Microsoft Visual Studio Solution File, Format Version 9.00
# Visual C++ Express 2005
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "rogue54", "rogue54.vcproj", "{9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Debug|Win32.ActiveCfg = Debug|Win32
{9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Debug|Win32.Build.0 = Debug|Win32
{9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Release|Win32.ActiveCfg = Release|Win32
{9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

396
src/cc/rogue/rogue54.vcproj Normal file
View File

@@ -0,0 +1,396 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="rogue54"
ProjectGUID="{9EA0D326-8097-4ADA-82EA-4DB1F5CAA8F6}"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
InlineFunctionExpansion="0"
AdditionalIncludeDirectories="../pdcurses"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_DEPRECATE;ALLSCORES;MASTER;SCOREFILE=\&quot;rogue54.scr\&quot;;LOCKFILE=\&quot;rogue54.lck\&quot;"
StringPooling="true"
MinimalRebuild="false"
ExceptionHandling="0"
BasicRuntimeChecks="3"
RuntimeLibrary="0"
BufferSecurityCheck="true"
EnableFunctionLevelLinking="true"
DisableLanguageExtensions="false"
ForceConformanceInForLoopScope="true"
UsePrecompiledHeader="0"
BrowseInformation="0"
WarningLevel="4"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
CompileAs="1"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="Ws2_32.lib pdcurses.lib advapi32.lib shfolder.lib user32.lib"
OutputFile="$(OutDir)/rogue54.exe"
LinkIncremental="2"
AdditionalLibraryDirectories="..\pdcurses"
IgnoreAllDefaultLibraries="false"
IgnoreDefaultLibraryNames=""
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/rogue54.pdb"
SubSystem="1"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="1"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC70.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="2"
InlineFunctionExpansion="1"
OmitFramePointers="true"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS"
StringPooling="true"
RuntimeLibrary="0"
EnableFunctionLevelLinking="true"
UsePrecompiledHeader="2"
WarningLevel="3"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="$(OutDir)/rogue54.exe"
LinkIncremental="1"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm"
>
<File
RelativePath="armor.c"
>
</File>
<File
RelativePath="chase.c"
>
</File>
<File
RelativePath="command.c"
>
</File>
<File
RelativePath="daemon.c"
>
</File>
<File
RelativePath="daemons.c"
>
</File>
<File
RelativePath="extern.c"
>
</File>
<File
RelativePath="fight.c"
>
</File>
<File
RelativePath="findpw.c"
>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="init.c"
>
</File>
<File
RelativePath="io.c"
>
</File>
<File
RelativePath="list.c"
>
</File>
<File
RelativePath="mach_dep.c"
>
</File>
<File
RelativePath="main.c"
>
</File>
<File
RelativePath="mdport.c"
>
</File>
<File
RelativePath="misc.c"
>
</File>
<File
RelativePath="monsters.c"
>
</File>
<File
RelativePath="move.c"
>
</File>
<File
RelativePath="new_level.c"
>
</File>
<File
RelativePath="options.c"
>
</File>
<File
RelativePath="pack.c"
>
</File>
<File
RelativePath="passages.c"
>
</File>
<File
RelativePath="potions.c"
>
</File>
<File
RelativePath="rings.c"
>
</File>
<File
RelativePath="rip.c"
>
</File>
<File
RelativePath="rooms.c"
>
</File>
<File
RelativePath="save.c"
>
</File>
<File
RelativePath="scedit.c"
>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="scmisc.c"
>
<FileConfiguration
Name="Debug|Win32"
ExcludedFromBuild="true"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath="scrolls.c"
>
</File>
<File
RelativePath="state.c"
>
</File>
<File
RelativePath="sticks.c"
>
</File>
<File
RelativePath="things.c"
>
</File>
<File
RelativePath="vers.c"
>
</File>
<File
RelativePath="weapons.c"
>
</File>
<File
RelativePath="wizard.c"
>
</File>
<File
RelativePath="xcrypt.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc"
>
<File
RelativePath="extern.h"
>
</File>
<File
RelativePath="rogue.h"
>
</File>
<File
RelativePath="score.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
>
</Filter>
<File
RelativePath="LICENSE.TXT"
>
</File>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

472
src/cc/rogue/rooms.c Normal file
View File

@@ -0,0 +1,472 @@
/*
* Create the layout for the new level
*
* @(#)rooms.c 4.45 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <ctype.h>
//#include <curses.h>
#include "rogue.h"
typedef struct spot { /* position matrix for maze positions */
int nexits;
coord exits[4];
int used;
} SPOT;
#define GOLDGRP 1
/*
* do_rooms:
* Create rooms and corridors with a connectivity graph
*/
void
do_rooms(struct rogue_state *rs)
{
int i;
struct room *rp;
THING *tp;
int left_out;
static coord top;
coord bsze; /* maximum room size */
coord mp;
bsze.x = NUMCOLS / 3;
bsze.y = NUMLINES / 3;
/*
* Clear things for a new level
*/
for (rp = rooms; rp < &rooms[MAXROOMS]; rp++)
{
rp->r_goldval = 0;
rp->r_nexits = 0;
rp->r_flags = 0;
}
/*
* Put the gone rooms, if any, on the level
*/
left_out = rnd(4);
for (i = 0; i < left_out; i++)
rooms[rnd_room()].r_flags |= ISGONE;
/*
* dig and populate all the rooms on the level
*/
for (i = 0, rp = rooms; i < MAXROOMS; rp++, i++)
{
/*
* Find upper left corner of box that this room goes in
*/
top.x = (i % 3) * bsze.x + 1;
top.y = (i / 3) * bsze.y;
if (rp->r_flags & ISGONE)
{
/*
* Place a gone room. Make certain that there is a blank line
* for passage drawing.
*/
do
{
rp->r_pos.x = top.x + rnd(bsze.x - 2) + 1;
rp->r_pos.y = top.y + rnd(bsze.y - 2) + 1;
rp->r_max.x = -NUMCOLS;
rp->r_max.y = -NUMLINES;
} until (rp->r_pos.y > 0 && rp->r_pos.y < NUMLINES-1);
continue;
}
/*
* set room type
*/
if (rnd(10) < level - 1)
{
rp->r_flags |= ISDARK; /* dark room */
if (rnd(15) == 0)
rp->r_flags = ISMAZE; /* maze room */
}
/*
* Find a place and size for a random room
*/
if (rp->r_flags & ISMAZE)
{
rp->r_max.x = bsze.x - 1;
rp->r_max.y = bsze.y - 1;
if ((rp->r_pos.x = top.x) == 1)
rp->r_pos.x = 0;
if ((rp->r_pos.y = top.y) == 0)
{
rp->r_pos.y++;
rp->r_max.y--;
}
}
else
do
{
rp->r_max.x = rnd(bsze.x - 4) + 4;
rp->r_max.y = rnd(bsze.y - 4) + 4;
rp->r_pos.x = top.x + rnd(bsze.x - rp->r_max.x);
rp->r_pos.y = top.y + rnd(bsze.y - rp->r_max.y);
} until (rp->r_pos.y != 0);
draw_room(rp);
/*
* Put the gold in
*/
if (rnd(2) == 0 && (!amulet || level >= max_level))
{
THING *gold;
gold = new_item();
gold->o_goldval = rp->r_goldval = GOLDCALC;
find_floor(rp, &rp->r_gold, FALSE, FALSE);
gold->o_pos = rp->r_gold;
chat(rp->r_gold.y, rp->r_gold.x) = GOLD;
gold->o_flags = ISMANY;
gold->o_group = GOLDGRP;
gold->o_type = GOLD;
attach(lvl_obj, gold);
}
/*
* Put the monster in
*/
if (rnd(100) < (rp->r_goldval > 0 ? 80 : 25))
{
tp = new_item();
find_floor(rp, &mp, FALSE, TRUE);
new_monster(rs,tp, randmonster(FALSE), &mp);
give_pack(rs,tp);
}
}
}
/*
* draw_room:
* Draw a box around a room and lay down the floor for normal
* rooms; for maze rooms, draw maze.
*/
void
draw_room(struct room *rp)
{
int y, x;
if (rp->r_flags & ISMAZE)
do_maze(rp);
else
{
vert(rp, rp->r_pos.x); /* Draw left side */
vert(rp, rp->r_pos.x + rp->r_max.x - 1); /* Draw right side */
horiz(rp, rp->r_pos.y); /* Draw top */
horiz(rp, rp->r_pos.y + rp->r_max.y - 1); /* Draw bottom */
/*
* Put the floor down
*/
for (y = rp->r_pos.y + 1; y < rp->r_pos.y + rp->r_max.y - 1; y++)
for (x = rp->r_pos.x + 1; x < rp->r_pos.x + rp->r_max.x - 1; x++)
chat(y, x) = FLOOR;
}
}
/*
* vert:
* Draw a vertical line
*/
void
vert(struct room *rp, int startx)
{
int y;
for (y = rp->r_pos.y + 1; y <= rp->r_max.y + rp->r_pos.y - 1; y++)
chat(y, startx) = '|';
}
/*
* horiz:
* Draw a horizontal line
*/
void
horiz(struct room *rp, int starty)
{
int x;
for (x = rp->r_pos.x; x <= rp->r_pos.x + rp->r_max.x - 1; x++)
chat(starty, x) = '-';
}
/*
* do_maze:
* Dig a maze
*/
static int Maxy, Maxx, Starty, Startx;
static SPOT maze[NUMLINES/3+1][NUMCOLS/3+1];
void
do_maze(struct room *rp)
{
SPOT *sp;
int starty, startx;
static coord pos;
for (sp = &maze[0][0]; sp <= &maze[NUMLINES / 3][NUMCOLS / 3]; sp++)
{
sp->used = FALSE;
sp->nexits = 0;
}
Maxy = rp->r_max.y;
Maxx = rp->r_max.x;
Starty = rp->r_pos.y;
Startx = rp->r_pos.x;
starty = (rnd(rp->r_max.y) / 2) * 2;
startx = (rnd(rp->r_max.x) / 2) * 2;
pos.y = starty + Starty;
pos.x = startx + Startx;
putpass(&pos);
dig(starty, startx);
}
/*
* dig:
* Dig out from around where we are now, if possible
*/
void
dig(int y, int x)
{
coord *cp;
int cnt, newy, newx, nexty = 0, nextx = 0;
static coord pos;
static coord del[4] = {
{2, 0}, {-2, 0}, {0, 2}, {0, -2}
};
for (;;)
{
cnt = 0;
for (cp = del; cp <= &del[3]; cp++)
{
newy = y + cp->y;
newx = x + cp->x;
if (newy < 0 || newy > Maxy || newx < 0 || newx > Maxx)
continue;
if (flat(newy + Starty, newx + Startx) & F_PASS)
continue;
if (rnd(++cnt) == 0)
{
nexty = newy;
nextx = newx;
}
}
if (cnt == 0)
return;
accnt_maze(y, x, nexty, nextx);
accnt_maze(nexty, nextx, y, x);
if (nexty == y)
{
pos.y = y + Starty;
if (nextx - x < 0)
pos.x = nextx + Startx + 1;
else
pos.x = nextx + Startx - 1;
}
else
{
pos.x = x + Startx;
if (nexty - y < 0)
pos.y = nexty + Starty + 1;
else
pos.y = nexty + Starty - 1;
}
putpass(&pos);
pos.y = nexty + Starty;
pos.x = nextx + Startx;
putpass(&pos);
dig(nexty, nextx);
}
}
/*
* accnt_maze:
* Account for maze exits
*/
void
accnt_maze(int y, int x, int ny, int nx)
{
SPOT *sp;
coord *cp;
sp = &maze[y][x];
for (cp = sp->exits; cp < &sp->exits[sp->nexits]; cp++)
if (cp->y == ny && cp->x == nx)
return;
cp->y = ny;
cp->x = nx;
}
/*
* rnd_pos:
* Pick a random spot in a room
*/
void
rnd_pos(struct room *rp, coord *cp)
{
cp->x = rp->r_pos.x + rnd(rp->r_max.x - 2) + 1;
cp->y = rp->r_pos.y + rnd(rp->r_max.y - 2) + 1;
}
/*
* find_floor:
* Find a valid floor spot in this room. If rp is NULL, then
* pick a new room each time around the loop.
*/
bool
find_floor(struct room *rp, coord *cp, int limit, bool monst)
{
PLACE *pp;
int cnt;
char compchar = 0;
bool pickroom;
pickroom = (bool)(rp == NULL);
if (!pickroom)
compchar = ((rp->r_flags & ISMAZE) ? PASSAGE : FLOOR);
cnt = limit;
for (;;)
{
if (limit && cnt-- == 0)
return FALSE;
if (pickroom)
{
rp = &rooms[rnd_room()];
compchar = ((rp->r_flags & ISMAZE) ? PASSAGE : FLOOR);
}
rnd_pos(rp, cp);
pp = INDEX(cp->y, cp->x);
if (monst)
{
if (pp->p_monst == NULL && step_ok(pp->p_ch))
return TRUE;
}
else if (pp->p_ch == compchar)
return TRUE;
}
}
/*
* enter_room:
* Code that is executed whenver you appear in a room
*/
void
enter_room(struct rogue_state *rs,coord *cp)
{
struct room *rp;
THING *tp;
int y, x;
char ch;
rp = proom = roomin(rs,cp);
door_open(rs,rp);
if (!(rp->r_flags & ISDARK) && !on(player, ISBLIND))
for (y = rp->r_pos.y; y < rp->r_max.y + rp->r_pos.y; y++)
{
move(y, rp->r_pos.x);
for (x = rp->r_pos.x; x < rp->r_max.x + rp->r_pos.x; x++)
{
tp = moat(y, x);
ch = chat(y, x);
if (tp == NULL)
if (CCHAR(inch()) != ch)
addch(ch);
else
move(y, x + 1);
else
{
tp->t_oldch = ch;
if (!see_monst(tp))
if (on(player, SEEMONST))
{
standout();
addch(tp->t_disguise);
standend();
}
else
addch(ch);
else
addch(tp->t_disguise);
}
}
}
}
/*
* leave_room:
* Code for when we exit a room
*/
void
leave_room(struct rogue_state *rs,coord *cp)
{
PLACE *pp;
struct room *rp;
int y, x;
char floor;
char ch;
rp = proom;
if (rp->r_flags & ISMAZE)
return;
if (rp->r_flags & ISGONE)
floor = PASSAGE;
else if (!(rp->r_flags & ISDARK) || on(player, ISBLIND))
floor = FLOOR;
else
floor = ' ';
proom = &passages[flat(cp->y, cp->x) & F_PNUM];
for (y = rp->r_pos.y; y < rp->r_max.y + rp->r_pos.y; y++)
for (x = rp->r_pos.x; x < rp->r_max.x + rp->r_pos.x; x++)
{
move(y, x);
switch ( ch = CCHAR(inch()) )
{
case FLOOR:
if (floor == ' ' && ch != ' ')
addch(' ');
break;
default:
/*
* to check for monster, we have to strip out
* standout bit
*/
if (isupper(toascii(ch)))
{
if (on(player, SEEMONST))
{
standout();
addch(ch);
standend();
break;
}
pp = INDEX(y,x);
addch(pp->p_ch == DOOR ? DOOR : floor);
}
}
}
door_open(rs,rp);
}

455
src/cc/rogue/save.c Normal file
View File

@@ -0,0 +1,455 @@
/*
* save and restore routines
*
* @(#)save.c 4.33 (Berkeley) 06/01/83
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
//#include <stdlib.h>
//#include <sys/types.h>
//#include <sys/stat.h>
//#include <errno.h>
//#include <signal.h>
//#include <string.h>
//#include <curses.h>
#include "rogue.h"
#include "score.h"
typedef struct stat STAT;
extern char *version, *encstr;
static STAT sbuf;
/*
* save_game:
* Implement the "save game" command
*/
void
save_game(struct rogue_state *rs)
{
FILE *savef;
int c;
//auto
char buf[MAXSTR];
/*
* get file name
*/
mpos = 0;
over:
if (file_name[0] != '\0')
{
for (;;)
{
msg(rs,"save file (%s)? ", file_name);
c = readchar(rs);
mpos = 0;
if (c == ESCAPE)
{
msg(rs,"");
return;
}
else if (c == 'n' || c == 'N' || c == 'y' || c == 'Y')
break;
else
msg(rs,"please answer Y or N");
}
if (c == 'y' || c == 'Y')
{
addstr("Yes\n");
if ( rs->sleeptime != 0 )
refresh();
strcpy(buf, file_name);
goto gotfile;
}
}
do
{
mpos = 0;
msg(rs,"file name: ");
buf[0] = '\0';
if (get_str(rs,buf, stdscr) == QUIT)
{
quit_it:
msg(rs,"");
return;
}
mpos = 0;
gotfile:
/*
* test to see if the file exists
*/
if (stat(buf, &sbuf) >= 0)
{
for (;;)
{
msg(rs,"File exists. Do you wish to overwrite it?");
mpos = 0;
if ((c = readchar(rs)) == ESCAPE)
goto quit_it;
if (c == 'y' || c == 'Y')
break;
else if (c == 'n' || c == 'N')
goto over;
else
msg(rs,"Please answer Y or N");
}
msg(rs,"file name: %s", buf);
md_unlink(file_name);
}
strcpy(file_name, buf);
if ((savef = fopen(file_name, "w")) == NULL)
msg(rs,strerror(errno));
} while (savef == NULL);
save_file(rs,savef,1);
/* NOTREACHED */
}
/*
* auto_save:
* Automatically save a file. This is used if a HUP signal is
* recieved
*/
void
auto_save(int sig)
{
FILE *savef;
NOOP(sig);
md_ignoreallsignals();
if (file_name[0] != '\0' && ((savef = fopen(file_name, "w")) != NULL ||
(md_unlink_open_file(file_name, savef) >= 0 && (savef = fopen(file_name, "w")) != NULL)))
save_file(&globalR,savef,1);
my_exit(0);
}
/*
* save_file:
* Write the saved game on the file
*/
char *rogue_packfname(struct rogue_state *rs,char *fname)
{
sprintf(fname,"rogue.%llu.pack",(long long)rs->seed);
return(fname);
}
void
save_file(struct rogue_state *rs,FILE *savef,int32_t guiflag)
{
char buf[80],fname[512]; int32_t i,n,nonz,histo[0x100]; FILE *fp;
memset(&rs->P,0,sizeof(rs->P));
mvcur(0, COLS - 1, LINES - 1, 0);
putchar('\n');
endwin();
resetltchars();
md_chmod(file_name, 0400);
if ( guiflag != 0 )
{
encwrite(version, strlen(version)+1, savef);
sprintf(buf,"%d x %d\n", LINES, COLS);
encwrite(buf,80,savef);
}
rs_save_file(rs,savef);
n = sizeof(rs->P) - sizeof(rs->P.roguepack) + sizeof(rs->P.roguepack[0])*rs->P.packsize;
memset(histo,0,sizeof(histo));
for (i=0; i<n; i++)
{
//fprintf(stderr,"%02x",((uint8_t *)&rs->P)[i]);
histo[((uint8_t *)&rs->P)[i]]++;
rs->playerdata[i] = ((uint8_t *)&rs->P)[i];
}
rs->playersize = n;
//fprintf(stderr," packsize.%d n.%d\n",rs->P.packsize,n);
if ( (fp= fopen(rogue_packfname(rs,fname),"wb")) != 0 )
{
fwrite(&rs->P,1,n,fp);
fclose(fp);
}
if ( 0 )
{
for (i=nonz=0; i<0x100; i++)
if ( histo[i] != 0 )
fprintf(stderr,"(%d %d) ",i,histo[i]), nonz++;
fprintf(stderr,"nonz.%d\n",nonz);
}
fflush(savef);
fclose(savef);
if ( guiflag != 0 )
my_exit(0);
}
int32_t rogue_restorepack(struct rogue_state *rs)
{
FILE *fp; char fname[512]; int32_t retflag = -1;
memset(&rs->P,0,sizeof(rs->P));
if ( (fp= fopen(rogue_packfname(rs,fname),"rb")) != 0 )
{
if ( fread(&rs->P,1,sizeof(rs->P) - sizeof(rs->P.roguepack),fp) == sizeof(rs->P) - sizeof(rs->P.roguepack) )
{
if ( rs->P.packsize > 0 && rs->P.packsize <= MAXPACK )
{
if ( fread(&rs->P.roguepack,1,rs->P.packsize*sizeof(rs->P.roguepack[0]),fp) == rs->P.packsize*sizeof(rs->P.roguepack[0]) )
{
fprintf(stderr,"roguepack[%d] restored\n",rs->P.packsize);
retflag = 0;
}
}
}
}
if ( retflag < 0 )
memset(&rs->P,0,sizeof(rs->P));
return(retflag);
}
/*
* restore:
* Restore a saved game from a file with elaborate checks for file
* integrity from cheaters
*/
bool
restore(struct rogue_state *rs,char *file, char **envp)
{
FILE *inf;
int syml,l, cols;
extern char **environ;
//auto
char buf[MAXSTR];
//auto
STAT sbuf2;
if (strcmp(file, "-r") == 0)
file = file_name;
md_tstphold();
if ((inf = fopen(file,"r")) == NULL)
{
perror(file);
return FALSE;
}
stat(file, &sbuf2);
syml = is_symlink(file);
fflush(stdout);
encread(buf, (unsigned) strlen(version) + 1, inf);
if (strcmp(buf, version) != 0)
{
printf("Sorry, saved game is out of date.\n");
return FALSE;
}
encread(buf,80,inf);
sscanf(buf,"%d x %d\n", &l, &cols);
initscr(); /* Start up cursor package */
keypad(stdscr, 1);
if (l > LINES)
{
endwin();
printf("Sorry, original game was played on a screen with %d lines.\n",l);
printf("Current screen only has %d lines. Unable to restore game\n",LINES);
return(FALSE);
}
if (cols > COLS)
{
endwin();
printf("Sorry, original game was played on a screen with %d columns.\n",cols);
printf("Current screen only has %d columns. Unable to restore game\n",COLS);
return(FALSE);
}
hw = newwin(LINES, COLS, 0, 0);
setup();
rs_restore_file(inf);
/*
* we do not close the file so that we will have a hold of the
* inode for as long as possible
*/
if (
#ifdef MASTER
!wizard &&
#endif
md_unlink_open_file(file, inf) < 0)
{
printf("Cannot unlink file\n");
return FALSE;
}
mpos = 0;
/* printw(0, 0, "%s: %s", file, ctime(&sbuf2.st_mtime)); */
/*
printw("%s: %s", file, ctime(&sbuf2.st_mtime));
*/
clearok(stdscr,TRUE);
/*
* defeat multiple restarting from the same place
*/
#ifdef MASTER
if (!wizard)
#endif
if (sbuf2.st_nlink != 1 || syml)
{
endwin();
printf("\nCannot restore from a linked file\n");
return FALSE;
}
if (pstats.s_hpt <= 0)
{
endwin();
printf("\n\"He's dead, Jim\"\n");
return FALSE;
}
md_tstpresume();
environ = envp;
strcpy(file_name, file);
clearok(curscr, TRUE);
srand((int32_t)rs->seed);//md_getpid());
msg(rs,"file name: %s", file);
playit(rs);
/*NOTREACHED*/
return(0);
}
/*
* encwrite:
* Perform an encrypted write
*/
#define CRYPT_ENABLE 0
size_t
encwrite(char *start, size_t size, FILE *outf)
{
char *e1, *e2, fb;
int temp;
extern char *statlist;
size_t o_size = size;
e1 = encstr;
e2 = statlist;
fb = 0;
while(size)
{
if ( CRYPT_ENABLE )
{
if (putc(*start++ ^ *e1 ^ *e2 ^ fb, outf) == EOF)
break;
temp = *e1++;
fb = fb + ((char) (temp * *e2++));
if (*e1 == '\0')
e1 = encstr;
if (*e2 == '\0')
e2 = statlist;
}
else if ( putc(*start++,outf) == EOF )
break;
size--;
}
return(o_size - size);
}
/*
* encread:
* Perform an encrypted read
*/
size_t
encread(char *start, size_t size, FILE *inf)
{
char *e1, *e2, fb;
int temp;
size_t read_size;
extern char *statlist;
fb = 0;
if ((read_size = fread(start,1,size,inf)) == 0 || read_size == -1)
return(read_size);
if ( CRYPT_ENABLE )
{
e1 = encstr;
e2 = statlist;
while (size--)
{
*start++ ^= *e1 ^ *e2 ^ fb;
temp = *e1++;
fb = fb + (char)(temp * *e2++);
if (*e1 == '\0')
e1 = encstr;
if (*e2 == '\0')
e2 = statlist;
}
}
return(read_size);
}
static char scoreline[100];
/*
* read_scrore
* Read in the score file
*/
void
rd_score(SCORE *top_ten)
{
unsigned int i;
if (scoreboard == NULL)
return;
rewind(scoreboard);
for(i = 0; i < numscores; i++)
{
encread(top_ten[i].sc_name, MAXSTR, scoreboard);
encread(scoreline, 100, scoreboard);
sscanf(scoreline, " %u %d %u %hu %d %x \n",
&top_ten[i].sc_uid, &top_ten[i].sc_score,
&top_ten[i].sc_flags, &top_ten[i].sc_monster,
&top_ten[i].sc_level, &top_ten[i].sc_time);
}
rewind(scoreboard);
}
/*
* write_scrore
* Read in the score file
*/
void
wr_score(SCORE *top_ten)
{
unsigned int i;
if (scoreboard == NULL)
return;
rewind(scoreboard);
for(i = 0; i < numscores; i++)
{
memset(scoreline,0,100);
encwrite(top_ten[i].sc_name, MAXSTR, scoreboard);
sprintf(scoreline, " %u %d %u %hu %d %x \n",
top_ten[i].sc_uid, top_ten[i].sc_score,
top_ten[i].sc_flags, top_ten[i].sc_monster,
top_ten[i].sc_level, top_ten[i].sc_time);
encwrite(scoreline,100,scoreboard);
}
rewind(scoreboard);
}

29
src/cc/rogue/score.h Normal file
View File

@@ -0,0 +1,29 @@
/*
* Score file structure
*
* @(#)score.h 4.6 (Berkeley) 02/05/99
*
* Rogue: Exploring the Dungeons of Doom
* Copyright (C) 1980-1983, 1985, 1999 Michael Toy, Ken Arnold and Glenn Wichman
* All rights reserved.
*
* See the file LICENSE.TXT for full copyright and licensing information.
*/
#ifndef H_SCORE_H
#define H_SCORE_H
struct sc_ent {
unsigned int sc_uid;
int sc_score;
unsigned int sc_flags;
unsigned short sc_monster;
char sc_name[MAXSTR];
int sc_level;
unsigned int sc_time;
};
typedef struct sc_ent SCORE;
void rd_score(SCORE *top_ten);
void wr_score(SCORE *top_ten);
#endif

Some files were not shown because too many files have changed in this diff Show More